new GalleryPageFactory(() => new PlatformSpecificsGallery(), "Platform Specifics"),
new GalleryPageFactory(() => new NativeBindingGalleryPage(), "Native Binding Controls Gallery"),
new GalleryPageFactory(() => new XamlNativeViews(), "Xaml Native Views Gallery"),
+ new GalleryPageFactory(() => new CharacterSpacingGallery(), "CharacterSpacing Views Gallery"),
new GalleryPageFactory(() => new AppLinkPageGallery(), "App Link Page Gallery"),
new GalleryPageFactory(() => new NestedNativeControlGalleryPage(), "Nested Native Controls Gallery"),
new GalleryPageFactory(() => new CellForceUpdateSizeGalleryPage(), "Cell Force Update Size Gallery"),
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+ x:Class="Xamarin.Forms.Controls.GalleryPages.CharacterSpacingGallery" Visual="Material">
+
+ <StackLayout>
+ <Label>
+ <Label.FormattedText>
+ <FormattedString>
+ <Span Text="CharacterSpacing" />
+ <Span Text=": " />
+ <Span Text="0" x:Name="CharacterSpacingValue" />
+ </FormattedString>
+ </Label.FormattedText>
+ </Label>
+ <Slider Minimum="-10" Maximum="10" Value="0" ValueChanged="Slider_OnValueChanged" MaximumTrackColor="Gray"
+ MinimumTrackColor="Gray" Margin="20,0"/>
+
+ <ScrollView>
+ <StackLayout>
+ <Label Text="Welcome to Xamarin.Forms! - Label" CharacterSpacing="0" x:Name="Label" TextColor="Red"/>
+ <Label>
+ <Label.FormattedText>
+ <FormattedString>
+ <Span Text="Welcome to Xamarin.Forms! - Span" CharacterSpacing="0" x:Name="Span" TextColor="Red"/>
+ </FormattedString>
+ </Label.FormattedText>
+ </Label>
+ <Entry Text="Welcome to Xamarin.Forms! - Entry" CharacterSpacing="0" x:Name="Entry" TextColor="Red" PlaceholderColor="BlueViolet"/>
+ <Entry Placeholder="Welcome to Xamarin.Forms! - Entry" CharacterSpacing="0" x:Name="PlaceholderEntry" TextColor="Red" PlaceholderColor="BlueViolet"/>
+ <Editor Text="Welcome to Xamarin.Forms! - Editor" CharacterSpacing="0" x:Name="Editor" TextColor="Red" PlaceholderColor="BlueViolet"/>
+ <Editor Placeholder="Welcome to Xamarin.Forms! - Editor" CharacterSpacing="0" x:Name="PlaceholderEditor" TextColor="Red" PlaceholderColor="BlueViolet"/>
+ <DatePicker Date="2019-01-01" CharacterSpacing="0" x:Name="DatePicker" TextColor="Red"/>
+ <TimePicker Time="10:10" CharacterSpacing="0" x:Name="TimePicker" TextColor="Red"/>
+ <Picker Title="Welcome to Xamarin.Forms! - Picker" CharacterSpacing="0" x:Name="Picker" TextColor="Red" TitleColor="BlueViolet">
+ <Picker.Items>
+ <x:String>Welcome to Xamarin.Forms1</x:String>
+ <x:String>Welcome to Xamarin.Forms2</x:String>
+ </Picker.Items>
+ </Picker>
+ <SearchBar Text="Welcome to Xamarin.Forms! - SearchBar" CharacterSpacing="0" x:Name="SearchBar" TextColor="Red" PlaceholderColor="BlueViolet"/>
+ <SearchBar Placeholder="Welcome to Xamarin.Forms! - SearchBar" CharacterSpacing="0" x:Name="PlaceholderSearchBar" TextColor="Red" PlaceholderColor="BlueViolet"/>
+ <Button Text="Welcome to Xamarin.Forms! - Button" CharacterSpacing="0" x:Name="Button" TextColor="Red"/>
+ </StackLayout>
+ </ScrollView>
+ </StackLayout>
+
+
+</ContentPage>
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Controls.GalleryPages
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class CharacterSpacingGallery : ContentPage
+ {
+ public CharacterSpacingGallery()
+ {
+ InitializeComponent();
+ }
+
+ void Slider_OnValueChanged(object sender, ValueChangedEventArgs e)
+ {
+ CharacterSpacingValue.Text = e.NewValue.ToString();
+ Button.CharacterSpacing = e.NewValue;
+ DatePicker.CharacterSpacing = e.NewValue;
+ Editor.CharacterSpacing = e.NewValue;
+ Entry.CharacterSpacing = e.NewValue;
+ PlaceholderEntry.CharacterSpacing = e.NewValue;
+ PlaceholderEditor.CharacterSpacing = e.NewValue;
+ Label.CharacterSpacing = e.NewValue;
+ Picker.CharacterSpacing = e.NewValue;
+ SearchBar.CharacterSpacing = e.NewValue;
+ PlaceholderSearchBar.CharacterSpacing = e.NewValue;
+ TimePicker.CharacterSpacing = e.NewValue;
+ Span.CharacterSpacing = e.NewValue;
+ }
+ }
+}
\ No newline at end of file
<Compile Update="GalleryPages\CollectionViewGalleries\SelectionGalleries\PreselectedItemsGallery.xaml.cs">
<DependentUpon>PreselectedItemsGallery.xaml</DependentUpon>
</Compile>
+ <Compile Update="GalleryPages\CharacterSpacingGallery.xaml.cs">
+ <DependentUpon>CharacterSpacingGallery.xaml</DependentUpon>
+ </Compile>
<Compile Update="GalleryPages\VisualStateManagerGalleries\OnPlatformExample.xaml.cs">
<DependentUpon>OnPlatformExample.xaml</DependentUpon>
</Compile>
<EmbeddedResource Update="GalleryPages\BindableLayoutGalleryPage.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
+ <EmbeddedResource Update="GalleryPages\CharacterSpacingGallery.xaml">
+ <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+ </EmbeddedResource>
<EmbeddedResource Update="GalleryPages\CollectionViewGalleries\EmptyViewGalleries\EmptyViewSwapGallery.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
public static readonly BindableProperty FontProperty = FontElement.FontProperty;
public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
bool IButtonElement.IsEnabledCore
{
set { SetValueCore(IsEnabledProperty, value); }
{
}
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
+
void IBorderElement.OnBorderColorPropertyChanged(Color oldValue, Color newValue)
{
}
namespace Xamarin.Forms
{
[RenderWith(typeof(_DatePickerRenderer))]
- public class DatePicker : View, IFontElement, ITextElement,IElementConfiguration<DatePicker>
+ public class DatePicker : View, IFontElement, ITextElement, IElementConfiguration<DatePicker>
{
public static readonly BindableProperty FormatProperty = BindableProperty.Create(nameof(Format), typeof(string), typeof(DatePicker), "d");
validateValue: ValidateMaximumDate, coerceValue: CoerceMaximumDate);
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
-
+
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;
public static readonly BindableProperty FontSizeProperty = FontElement.FontSizeProperty;
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
public FontAttributes FontAttributes
{
get { return (FontAttributes)GetValue(FontAttributesProperty); }
void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
{
}
+
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
}
}
\ No newline at end of file
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
public static readonly BindableProperty PlaceholderProperty = PlaceholderElement.PlaceholderProperty;
public static readonly BindableProperty PlaceholderColorProperty = PlaceholderElement.PlaceholderColorProperty;
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
public string Placeholder {
get => (string)GetValue(PlaceholderElement.PlaceholderProperty);
set => SetValue(PlaceholderElement.PlaceholderProperty, value);
{
}
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
+
private static void OnTextChanged(Editor bindable, string oldValue, string newValue)
{
bindable.TextChanged?.Invoke(bindable, new TextChangedEventArgs(oldValue, newValue));
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
public static readonly BindableProperty HorizontalTextAlignmentProperty = TextAlignmentElement.HorizontalTextAlignmentProperty;
public static readonly BindableProperty FontFamilyProperty = FontElement.FontFamilyProperty;
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
public FontAttributes FontAttributes
{
get { return (FontAttributes)GetValue(FontAttributesProperty); }
{
}
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
+
void ITextAlignmentElement.OnHorizontalTextAlignmentPropertyChanged(TextAlignment oldValue, TextAlignment newValue)
{
}
//note to implementor: but implement this method explicitly
void OnTextColorPropertyChanged(Color oldValue, Color newValue);
+
+ double CharacterSpacing { get; }
+
+ //note to implementor: but implement these methods explicitly
+ void OnCharacterSpacingPropertyChanged(double oldValue, double newValue);
}
-}
\ No newline at end of file
+}
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
public static readonly BindableProperty FontProperty = FontElement.FontProperty;
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(Label), default(string), propertyChanged: OnTextPropertyChanged);
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
public TextAlignment VerticalTextAlignment
{
get { return (TextAlignment)GetValue(VerticalTextAlignmentProperty); }
{
}
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
+
public override IList<GestureElement> GetChildElements(Point point)
{
if (FormattedText?.Spans == null || FormattedText?.Spans.Count == 0)
{
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
public static readonly BindableProperty TitleProperty =
BindableProperty.Create(nameof(Title), typeof(string), typeof(Picker), default(string));
set { SetValue(SelectedItemProperty, value); }
}
- public Color TextColor {
+ public Color TextColor
+ {
get { return (Color)GetValue(TextElement.TextColorProperty); }
set { SetValue(TextElement.TextColorProperty, value); }
}
- public string Title {
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
+ public string Title
+ {
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
{
}
+
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
}
}
\ No newline at end of file
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
readonly Lazy<PlatformConfigurationRegistry<SearchBar>> _platformConfigurationRegistry;
public Color CancelButtonColor
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
bool IsEnabledCore
{
set { SetValueCore(IsEnabledProperty, value); }
{
}
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
void ITextAlignmentElement.OnHorizontalTextAlignmentPropertyChanged(TextAlignment oldValue, TextAlignment newValue)
{
}
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
- void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
- {
- }
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
public Color TextColor
{
set { SetValue(FontFamilyProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
[TypeConverter(typeof(FontSizeConverter))]
public double FontSize
{
((SearchHandler)bindable).OnCommandParameterChanged();
}
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+
+ }
+
+ void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
+ {
+
+ }
+
static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var self = (SearchHandler)bindable;
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
[Obsolete("Foreground is obsolete as of version 3.1.0. Please use the TextColor property instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty ForegroundColorProperty = TextColorProperty;
{
}
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ }
+
internal override void ValidateGesture(IGestureRecognizer gesture)
{
switch (gesture)
BindableProperty.Create(nameof(ITextElement.TextColor), typeof(Color), typeof(ITextElement), Color.Default,
propertyChanged: OnTextColorPropertyChanged);
+ public static readonly BindableProperty CharacterSpacingProperty =
+ BindableProperty.Create(nameof(ITextElement.CharacterSpacing), typeof(double), typeof(ITextElement), 0.0d,
+ propertyChanged: OnCharacterSpacingPropertyChanged);
+
static void OnTextColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
((ITextElement)bindable).OnTextColorPropertyChanged((Color)oldValue, (Color)newValue);
}
+
+ static void OnCharacterSpacingPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ ((ITextElement)bindable).OnCharacterSpacingPropertyChanged((double)oldValue, (double)newValue);
+ }
+
}
}
\ No newline at end of file
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
+ public static readonly BindableProperty CharacterSpacingProperty = TextElement.CharacterSpacingProperty;
+
public static readonly BindableProperty TimeProperty = BindableProperty.Create(nameof(Time), typeof(TimeSpan), typeof(TimePicker), new TimeSpan(0), BindingMode.TwoWay, (bindable, value) =>
{
var time = (TimeSpan)value;
set { SetValue(TextElement.TextColorProperty, value); }
}
+ public double CharacterSpacing
+ {
+ get { return (double)GetValue(TextElement.CharacterSpacingProperty); }
+ set { SetValue(TextElement.CharacterSpacingProperty, value); }
+ }
+
public TimeSpan Time
{
get { return (TimeSpan)GetValue(TimeProperty); }
void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
{
}
+
+ void ITextElement.OnCharacterSpacingPropertyChanged(double oldValue, double newValue)
+ {
+ InvalidateMeasure();
+ }
+
}
}
\ No newline at end of file
UpdatePrimaryColors();
else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
UpdateInputTransparent();
+ else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
ElementPropertyChanged?.Invoke(this, e);
}
ViewCompat.SetBackgroundTintList(this, MaterialColors.CreateButtonBackgroundColors(background));
}
+ void UpdateCharacterSpacing()
+ {
+ LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
IPlatformElementConfiguration<PlatformConfiguration.Android, Button> OnThisPlatform() =>
_platformElementConfiguration ?? (_platformElementConfiguration = Element.OnThisPlatform());
_textInputLayout.BoxBackgroundColor = MaterialColors.CreateEntryFilledInputBackgroundColor(Element.BackgroundColor, Element.TextColor);
}
- protected override void UpdatePlaceHolderText() => _textInputLayout.SetHint(string.Empty, Element);
+ protected override void UpdatePlaceHolderText()
+ {
+ _textInputLayout.SetHint(Element.Title, Element);
+ }
protected override void UpdateTitleColor() => ApplyTheme();
protected override void UpdateTextColor() => ApplyTheme();
protected virtual void ApplyTheme() => _textInputLayout?.ApplyTheme(Element.TextColor, Color.Default);
using System;
using System.ComponentModel;
using CoreGraphics;
+using Foundation;
using MaterialComponents;
using UIKit;
using Xamarin.Forms.Platform.iOS;
UpdateTextColor();
_buttonLayoutManager?.Update();
ApplyTheme();
+ UpdateCharacterSpacing();
}
}
{
UpdateBorder();
}
+ else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+ {
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == Button.CornerRadiusProperty.PropertyName)
{
UpdateCornerRadius();
}
}
+ void UpdateCharacterSpacing()
+ {
+ var attributedString = new NSMutableAttributedString(Element.Text ?? string.Empty).AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+ Control.SetAttributedTitle(attributedString, UIControlState.Normal);
+ Control.SetAttributedTitle(attributedString, UIControlState.Highlighted);
+ Control.SetAttributedTitle(attributedString, UIControlState.Disabled);
+ }
void UpdateTextColor()
{
if (_buttonScheme.ColorScheme is SemanticColorScheme colorScheme)
using UIKit;
using MaterialComponents;
using System;
+using Foundation;
using Xamarin.Forms.Platform.iOS;
namespace Xamarin.Forms.Material.iOS
Control.UpdatePlaceholder(this);
}
+ protected internal override void UpdateCharacterSpacing()
+ {
+ Control.AttributedText = Control.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+ }
+
protected internal override void UpdateText()
{
if (!_hackHasRan)
Color IMaterialEntryRenderer.PlaceholderColor => Element?.PlaceholderColor ?? Color.Default;
Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
}
-}
\ No newline at end of file
+}
{
base.OnElementChanged(e);
UpdatePlaceholder();
+ UpdateCharacterSpacing();
}
string IMaterialEntryRenderer.Placeholder => string.Empty;
Color IMaterialEntryRenderer.TextColor => Element?.TextColor ?? Color.Default;
Color IMaterialEntryRenderer.BackgroundColor => Element?.BackgroundColor ?? Color.Default;
}
-}
\ No newline at end of file
+}
UpdateEnabled();
else if (e.PropertyName == Button.FontProperty.PropertyName)
UpdateFont();
+ else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
base.OnElementPropertyChanged(sender, e);
}
UpdateTextColor();
UpdateEnabled();
UpdateBackgroundColor();
+ UpdateCharacterSpacing();
}
void UpdateEnabled()
_textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ NativeButton.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
+ }
+
void IOnClickListener.OnClick(AView v) => ButtonElementManager.OnClick(Element, Element, v);
bool IOnTouchListener.OnTouch(AView v, MotionEvent e) => ButtonElementManager.OnTouch(Element, Element, v, e);
UpdateFont();
UpdatePicker();
UpdateTextColor();
+ UpdateCharacterSpacing();
}
base.OnElementChanged(e);
UpdatePicker();
else if (e.PropertyName == Picker.SelectedIndexProperty.PropertyName)
UpdatePicker();
+ else if (e.PropertyName == Picker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Picker.TextColorProperty.PropertyName)
UpdateTextColor();
else if (e.PropertyName == Picker.FontAttributesProperty.PropertyName || e.PropertyName == Picker.FontFamilyProperty.PropertyName || e.PropertyName == Picker.FontSizeProperty.PropertyName)
EditText.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
}
+ protected void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ EditText.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdatePicker()
{
UpdatePlaceHolderText();
_textColorSwitcher = _textColorSwitcher ?? new TextColorSwitcher(EditText.TextColors, Element.UseLegacyColorManagement());
_textColorSwitcher.UpdateTextColor(EditText, Element.TextColor);
}
- protected override void UpdatePlaceHolderText() => EditText.Hint = Element.Title;
+ protected override void UpdatePlaceHolderText()
+ {
+ EditText.Hint = Element.Title;
+ }
}
}
\ No newline at end of file
internal static bool IsHorizontal(this Button.ButtonContentLayout layout) =>
layout.Position == Button.ButtonContentLayout.ImagePosition.Left ||
layout.Position == Button.ButtonContentLayout.ImagePosition.Right;
+
+
+ internal static float ToEm(this double pt)
+ {
+ return (float)pt * 0.0624f; //Coefficient for converting Pt to Em
+ }
}
}
\ No newline at end of file
UpdateTextColor();
UpdateInputTransparent();
UpdateBackgroundColor();
+ UpdateCharacterSpacing();
_buttonLayoutManager?.Update();
ElevationHelper.SetElevation(this, e.NewElement);
{
UpdateFont();
}
+ else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+ {
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
{
UpdateInputTransparent();
_textColorSwitcher.Value.UpdateTextColor(this, Button.TextColor);
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ LetterSpacing = Button.CharacterSpacing.ToEm();
+ }
+ }
+
float IBorderVisualElementRenderer.ShadowRadius => ShadowRadius;
float IBorderVisualElementRenderer.ShadowDx => ShadowDx;
float IBorderVisualElementRenderer.ShadowDy => ShadowDy;
using Android.Text;
using Android.Util;
using Android.Views;
+using Android.Widget;
using AView = Android.Views.View;
namespace Xamarin.Forms.Platform.Android.FastRenderers
SkipNextInvalidate();
UpdateText();
UpdateLineHeight();
+ UpdateCharacterSpacing();
UpdateTextDecorations();
if (e.OldElement?.LineBreakMode != e.NewElement.LineBreakMode)
UpdateLineBreakMode();
UpdateText();
else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName)
UpdateLineBreakMode();
+ else if (e.PropertyName == Label.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations();
else if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName)
_lastSizeRequest = null;
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdateLineBreakMode()
{
this.SetLineBreakMode(Element);
UpdateText();
else if (e.PropertyName == Button.TextColorProperty.PropertyName)
UpdateTextColor();
+ else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
UpdateEnabled();
else if (e.PropertyName == Button.FontProperty.PropertyName)
UpdateText();
UpdateBitmap();
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdateEnabled();
UpdateBackgroundColor();
UpdatePadding();
_textColorSwitcher?.UpdateTextColor(Control, Element.TextColor);
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ Control.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
float IBorderVisualElementRenderer.ShadowRadius => Control.ShadowRadius;
float IBorderVisualElementRenderer.ShadowDx => Control.ShadowDx;
float IBorderVisualElementRenderer.ShadowDy => Control.ShadowDy;
UpdateMinimumDate();
UpdateMaximumDate();
UpdateTextColor();
+ UpdateCharacterSpacing();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
UpdateMaximumDate();
else if (e.PropertyName == DatePicker.TextColorProperty.PropertyName)
UpdateTextColor();
+ else if (e.PropertyName == DatePicker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == DatePicker.FontAttributesProperty.PropertyName || e.PropertyName == DatePicker.FontFamilyProperty.PropertyName || e.PropertyName == DatePicker.FontSizeProperty.PropertyName)
UpdateFont();
}
EditText.Text = date.ToString(Element.Format);
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ EditText.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdateFont()
{
EditText.Typeface = Element.ToTypeface();
UpdateText();
UpdateInputType();
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdateFont();
UpdateMaxLength();
UpdatePlaceholderColor();
UpdateInputType();
else if (e.PropertyName == Editor.TextColorProperty.PropertyName)
UpdateTextColor();
+ else if (e.PropertyName == Editor.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Editor.FontAttributesProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == Editor.FontFamilyProperty.PropertyName)
}
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ EditText.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdateText()
{
string newText = Element.Text ?? "";
UpdatePlaceHolderText();
EditText.Text = Element.Text;
UpdateInputType();
-
UpdateColor();
+ UpdateCharacterSpacing();
UpdateAlignment();
UpdateFont();
UpdatePlaceholderColor();
UpdateInputType();
else if (e.PropertyName == Entry.HorizontalTextAlignmentProperty.PropertyName)
UpdateAlignment();
+ else if (e.PropertyName == Entry.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Entry.FontAttributesProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == Entry.FontFamilyProperty.PropertyName)
EditText.Text = currentControlText.Substring(0, Element.MaxLength);
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ EditText.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdateReturnType()
{
if (Control == null || Element == null)
}
if (!span.IsDefault())
#pragma warning disable 618 // We will need to update this when .Font goes away
- spannable.SetSpan(new FontSpan(span.Font, view), start, end, SpanTypes.InclusiveInclusive);
+ spannable.SetSpan(new FontSpan(span.Font, view, span.CharacterSpacing.ToEm()), start, end, SpanTypes.InclusiveInclusive);
#pragma warning restore 618
else
- spannable.SetSpan(new FontSpan(defaultFont, view), start, end, SpanTypes.InclusiveInclusive);
+ spannable.SetSpan(new FontSpan(defaultFont, view, span.CharacterSpacing.ToEm()), start, end, SpanTypes.InclusiveInclusive);
if (span.IsSet(Span.TextDecorationsProperty))
spannable.SetSpan(new TextDecorationSpan(span), start, end, SpanTypes.InclusiveInclusive);
+
}
return spannable;
}
class FontSpan : MetricAffectingSpan
{
- public FontSpan(Font font, TextView view)
+ public FontSpan(Font font, TextView view, float characterSpacing)
{
Font = font;
TextView = view;
+ if (Forms.IsLollipopOrNewer)
+ {
+ CharacterSpacing = characterSpacing;
+ }
}
public Font Font { get; }
public TextView TextView { get; }
+ public float CharacterSpacing { get; }
+
public override void UpdateDrawState(TextPaint tp)
{
Apply(tp);
paint.SetTypeface(Font.ToTypeface());
float value = Font.ToScaledPixel();
paint.TextSize = TypedValue.ApplyDimension(ComplexUnitType.Sp, value, TextView.Resources.DisplayMetrics);
+ if (Forms.IsLollipopOrNewer)
+ {
+ paint.LetterSpacing = CharacterSpacing;
+ }
}
}
{
UpdateText();
UpdateLineBreakMode();
+ UpdateCharacterSpacing();
UpdateLineHeight();
UpdateGravity();
UpdateMaxLines();
UpdateGravity();
if (e.OldElement.MaxLines != e.NewElement.MaxLines)
UpdateMaxLines();
+ if (e.OldElement.CharacterSpacing != e.NewElement.CharacterSpacing)
+ UpdateCharacterSpacing();
+
}
UpdateTextDecorations();
UpdatePadding();
UpdateText();
else if (e.PropertyName == Label.FontProperty.PropertyName)
UpdateText();
+ else if (e.PropertyName == Label.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName)
UpdateLineBreakMode();
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
_view.SetLineBreakMode(Element);
_lastSizeRequest = null;
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer && Control is TextView textControl)
+ {
+ textControl.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdateLineHeight()
{
UpdateFont();
UpdatePicker();
UpdateTextColor();
+ UpdateCharacterSpacing();
}
base.OnElementChanged(e);
UpdatePicker();
else if (e.PropertyName == Picker.SelectedIndexProperty.PropertyName)
UpdatePicker();
+ else if (e.PropertyName == Picker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Picker.TextColorProperty.PropertyName)
UpdateTextColor();
else if (e.PropertyName == Picker.FontAttributesProperty.PropertyName || e.PropertyName == Picker.FontFamilyProperty.PropertyName || e.PropertyName == Picker.FontSizeProperty.PropertyName)
UpdatePicker();
}
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ Control.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdateFont()
{
Control.Typeface = Element.ToTypeface();
UpdateFont();
UpdateAlignment();
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdatePlaceholderColor();
UpdateMaxLength();
UpdateFont();
else if (e.PropertyName == SearchBar.FontFamilyProperty.PropertyName)
UpdateFont();
+ else if (e.PropertyName == SearchBar.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == SearchBar.FontSizeProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == SearchBar.HorizontalTextAlignmentProperty.PropertyName)
Control.SetQuery(Element.Text, false);
}
+ void UpdateCharacterSpacing()
+ {
+ if(!Forms.IsLollipopOrNewer)
+ return;
+
+ _editText = _editText ?? Control.GetChildrenOfType<EditText>().FirstOrDefault();
+
+ if (_editText != null)
+ {
+ _editText.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
void UpdateTextColor()
{
_textColorSwitcher?.UpdateTextColor(_editText, Element.TextColor);
SetTime(e.NewElement.Time);
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdateFont();
if ((int)Build.VERSION.SdkInt > 16)
SetTime(Element.Time);
else if (e.PropertyName == TimePicker.TextColorProperty.PropertyName)
UpdateTextColor();
+ else if (e.PropertyName == TimePicker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == TimePicker.FontAttributesProperty.PropertyName || e.PropertyName == TimePicker.FontFamilyProperty.PropertyName || e.PropertyName == TimePicker.FontSizeProperty.PropertyName)
UpdateFont();
}
EditText.Typeface = Element.ToTypeface();
EditText.SetTextSize(ComplexUnitType.Sp, (float)Element.FontSize);
}
-
+
+ void UpdateCharacterSpacing()
+ {
+ if (Forms.IsLollipopOrNewer)
+ {
+ EditText.LetterSpacing = Element.CharacterSpacing.ToEm();
+ }
+ }
+
abstract protected void UpdateTextColor();
}
_textColorSwitcher = _textColorSwitcher ?? new TextColorSwitcher(EditText.TextColors, Element.UseLegacyColorManagement());
_textColorSwitcher.UpdateTextColor(EditText, Element.TextColor);
}
- }
+
+ }
}
if (Element.IsSet(Button.BorderColorProperty) && Element.BorderColor != (Color)Button.BorderColorProperty.DefaultValue)
UpdateBorderColor();
+ if (Element.IsSet(Button.CharacterSpacingProperty))
+ UpdateCharacterSpacing();
+
if (Element.IsSet(Button.BorderWidthProperty) && Element.BorderWidth != (double)Button.BorderWidthProperty.DefaultValue)
UpdateBorderWidth();
{
UpdateContent();
}
+ else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+ {
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
{
UpdateBackground();
Control.BorderThickness = Element.BorderWidth == (double)Button.BorderWidthProperty.DefaultValue ? new WThickness(3) : new WThickness(Element.BorderWidth);
}
+ void UpdateCharacterSpacing()
+ {
+ Control.UpdateCharacterSpacing(Element.CharacterSpacing.ToEm());
+ }
+
async void UpdateContent()
{
var text = Element.Text;
using System;
using System.ComponentModel;
using System.Linq;
+using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Media;
using Xamarin.Forms.Internals;
UpdateMaximumDate();
UpdateDate(e.NewElement.Date);
UpdateFlowDirection();
+ UpdateCharacterSpacing();
}
base.OnElementChanged(e);
UpdateMinimumDate();
else if (e.PropertyName == DatePicker.TextColorProperty.PropertyName)
UpdateTextColor();
+ else if (e.PropertyName == DatePicker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateFlowDirection();
else if (e.PropertyName == DatePicker.FontAttributesProperty.PropertyName || e.PropertyName == DatePicker.FontFamilyProperty.PropertyName || e.PropertyName == DatePicker.FontSizeProperty.PropertyName)
{
Control.UpdateFlowDirection(Element);
}
-
+
+ void UpdateCharacterSpacing()
+ {
+ Control.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
void UpdateFont()
{
if (Control == null)
using System;
using System.ComponentModel;
+using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
UpdateText();
UpdateInputScope();
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdateFont();
UpdateTextAlignment();
UpdateFlowDirection();
{
UpdateText();
}
+ else if (e.PropertyName == Editor.CharacterSpacingProperty.PropertyName)
+ {
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
{
UpdateTextAlignment();
Control.InputScope = editor.Keyboard.ToInputScope();
}
+ void UpdateCharacterSpacing()
+ {
+ Control.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
void UpdateText()
{
string newText = Element.Text ?? "";
using System;
using System.ComponentModel;
using Windows.System;
+using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
UpdatePlaceholder();
UpdateTextColor();
UpdateFont();
+ UpdateCharacterSpacing();
UpdateAlignment();
UpdatePlaceholderColor();
UpdateMaxLength();
UpdatePlaceholder();
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
UpdateTextColor();
+ else if (e.PropertyName == Entry.CharacterSpacingProperty.PropertyName)
+ {
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == InputView.KeyboardProperty.PropertyName)
UpdateInputScope();
else if (e.PropertyName == InputView.IsSpellCheckEnabledProperty.PropertyName)
_fontApplied = true;
}
+ void UpdateCharacterSpacing()
+ {
+ Control.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
void UpdateInputScope()
{
Entry entry = Element;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
+using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
return max;
return value;
}
+
+
+ internal static int ToEm(this double pt)
+ {
+ return Convert.ToInt32( pt * 0.0624f * 1000); //Coefficient for converting Pt to Em. The value is uniform spacing between characters, in units of 1/1000 of an em.
+ }
}
}
\ No newline at end of file
-using Windows.UI.Xaml;
+using System.Linq;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using WContentPresenter = Windows.UI.Xaml.Controls.ContentPresenter;
_contentPresenter.CornerRadius = new Windows.UI.Xaml.CornerRadius(radius);
}
}
+
+ public void UpdateCharacterSpacing(int characterSpacing)
+ {
+ CharacterSpacing = characterSpacing;
+
+ if (_contentPresenter != null)
+ _contentPresenter.CharacterSpacing = CharacterSpacing;
+
+ if(Content is TextBlock tb)
+ {
+ tb.CharacterSpacing = CharacterSpacing;
+ }
+
+ if (Content is StackPanel sp)
+ {
+ foreach (var item in sp.Children)
+ {
+ if (item is TextBlock textBlock)
+ {
+ textBlock.CharacterSpacing = CharacterSpacing;
+ }
+ }
+ }
+
+ }
}
}
\ No newline at end of file
using System.Collections.Generic;
using System.ComponentModel;
using Windows.Foundation;
+using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
if (span.IsSet(Span.TextDecorationsProperty))
run.TextDecorations = (Windows.UI.Text.TextDecorations)span.TextDecorations;
+ run.CharacterSpacing = span.CharacterSpacing.ToEm();
+
return run;
}
}
UpdateTextDecorations(Control);
UpdateColor(Control);
UpdateAlign(Control);
+ UpdateCharacterSpacing(Control);
UpdateFont(Control);
UpdateLineBreakMode(Control);
UpdateMaxLines(Control);
UpdateFont(Control);
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations(Control);
+ else if (e.PropertyName == Label.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing(Control);
else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName)
UpdateLineBreakMode(Control);
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
}
}
+ void UpdateCharacterSpacing(TextBlock textBlock)
+ {
+ textBlock.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
+
void DetermineTruncatedTextWrapping(TextBlock textBlock)
{
if (Element.MaxLines > 1)
using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.ComponentModel;
+using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Core;
+using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
WireUpFormsVsm();
}
- Control.ItemsSource = ((LockableObservableListWrapper)Element.Items)._list;
-
+ Control.ItemsSource = GetItems(Element.Items);
UpdateTitle();
UpdateSelectedIndex();
+ UpdateCharacterSpacing();
}
base.OnElementChanged(e);
UpdateSelectedIndex();
else if (e.PropertyName == Picker.TitleProperty.PropertyName || e.PropertyName == Picker.TitleColorProperty.PropertyName)
UpdateTitle();
+ else if (e.PropertyName == Picker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Picker.TextColorProperty.PropertyName)
UpdateTextColor();
else if (e.PropertyName == Picker.FontAttributesProperty.PropertyName || e.PropertyName == Picker.FontFamilyProperty.PropertyName || e.PropertyName == Picker.FontSizeProperty.PropertyName)
});
}
+ void UpdateCharacterSpacing()
+ {
+ Control.CharacterSpacing = Element.CharacterSpacing.ToEm();
+
+ if (Control.Header is TextBlock header)
+ {
+ header.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
+ if (Control.SelectedValue is TextBlock item)
+ {
+ item.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
+ if(Control.ItemsSource is ObservableCollection<TextBlock> collection)
+ {
+ collection.ForEach(f=>f.CharacterSpacing = Control.CharacterSpacing);
+ }
+ }
+
+
+ TextBlock ConvertStrongToTextBlock(string text)
+ {
+ return new TextBlock{
+ Text = text,
+ CharacterSpacing = Control.CharacterSpacing
+ };
+ }
+
+ ObservableCollection<TextBlock> GetItems(IList<string> items)
+ {
+ return new ObservableCollection<TextBlock>(items.Select(ConvertStrongToTextBlock));
+ }
+
void UpdateFont()
{
if (Control == null)
if (!Element.IsSet(Picker.TitleColorProperty))
{
Control.HeaderTemplate = null;
- Control.Header = Element.Title;
+ Control.Header = new TextBlock
+ {
+ Text = Element.Title ?? string.Empty,
+ CharacterSpacing = Element.CharacterSpacing.ToEm(),
+ };
}
else
{
using System.ComponentModel;
+using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
UpdatePlaceholder();
UpdateCancelButtonColor();
UpdateAlignment();
+ UpdateCharacterSpacing();
UpdateFont();
UpdateTextColor();
UpdatePlaceholderColor();
UpdateAlignment();
else if (e.PropertyName == SearchBar.FontAttributesProperty.PropertyName)
UpdateFont();
+ else if (e.PropertyName == SearchBar.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == SearchBar.FontFamilyProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == SearchBar.FontSizeProperty.PropertyName)
_fontApplied = true;
}
+ void UpdateCharacterSpacing()
+ {
+ Control.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
void UpdatePlaceholder()
{
Control.PlaceholderText = Element.Placeholder ?? string.Empty;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
+using Windows.UI.Text;
using Windows.UI.Xaml.Media;
using Xamarin.Forms.Internals;
}
UpdateTime();
+ UpdateCharacterSpacing();
UpdateFlowDirection();
}
}
UpdateTextColor();
else if (e.PropertyName == TimePicker.FontAttributesProperty.PropertyName || e.PropertyName == TimePicker.FontFamilyProperty.PropertyName || e.PropertyName == TimePicker.FontSizeProperty.PropertyName)
UpdateFont();
+ else if (e.PropertyName == TimePicker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateFlowDirection();
Control.Time = Element.Time;
}
+ void UpdateCharacterSpacing()
+ {
+ Control.CharacterSpacing = Element.CharacterSpacing.ToEm();
+ }
+
void UpdateTextColor()
{
Color color = Element.TextColor;
+using Foundation;
using UIKit;
using Xamarin.Forms.Internals;
}
}
+ internal static NSMutableAttributedString AddCharacterSpacing(this NSMutableAttributedString attributedString, string text, double characterSpacing)
+ {
+ if (attributedString == null || attributedString.Length == 0)
+ {
+ attributedString = text == null ? new NSMutableAttributedString() : new NSMutableAttributedString(text);
+ }
+ else
+ {
+ attributedString = new NSMutableAttributedString(attributedString);
+ }
+
+ AddKerningAdjustment(attributedString, text, characterSpacing);
+
+ return attributedString;
+ }
+
+ internal static NSMutableAttributedString AddCharacterSpacing(this NSAttributedString attributedString, string text, double characterSpacing)
+ {
+ NSMutableAttributedString mutableAttributedString;
+ if (attributedString == null || attributedString.Length == 0)
+ {
+ mutableAttributedString = text == null ? new NSMutableAttributedString() : new NSMutableAttributedString(text);
+ }
+ else
+ {
+ mutableAttributedString = new NSMutableAttributedString(attributedString);
+ }
+
+ AddKerningAdjustment(mutableAttributedString, text, characterSpacing);
+
+ return mutableAttributedString;
+ }
+
+ internal static void AddKerningAdjustment(NSMutableAttributedString mutableAttributedString, string text, double characterSpacing)
+ {
+ if (!string.IsNullOrEmpty(text))
+ {
+ mutableAttributedString.AddAttribute
+ (
+ UIStringAttributeKey.KerningAdjustment,
+ NSObject.FromObject(characterSpacing), new NSRange(0, text.Length - 1)
+ );
+ }
+ }
+
internal static bool IsHorizontal(this Button.ButtonContentLayout layout) =>
layout.Position == Button.ButtonContentLayout.ImagePosition.Left ||
layout.Position == Button.ButtonContentLayout.ImagePosition.Right;
UpdateFont();
UpdateTextColor();
+ UpdateCharacterSpacing();
_buttonLayoutManager?.Update();
}
}
if (e.PropertyName == Button.TextColorProperty.PropertyName)
UpdateTextColor();
else if (e.PropertyName == Button.FontProperty.PropertyName)
+ {
UpdateFont();
+ }
+ else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+ {
+ UpdateCharacterSpacing();
+ }
+
}
protected override void SetAccessibilityLabel()
Control.TitleLabel.Font = Element.ToUIFont();
}
+ void UpdateCharacterSpacing()
+ {
+ var attributedString = new NSMutableAttributedString(Element.Text ?? string.Empty).AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+ Control.SetAttributedTitle(attributedString, UIControlState.Normal);
+ Control.SetAttributedTitle(attributedString, UIControlState.Highlighted);
+ Control.SetAttributedTitle(attributedString, UIControlState.Disabled);
+ }
+
public void SetImage(UIImage image) => _buttonLayoutManager.SetImage(image);
public UIImageView GetImage() => Control?.ImageView;
UpdateMaximumDate();
UpdateMinimumDate();
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdateFlowDirection();
}
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == DatePicker.DateProperty.PropertyName || e.PropertyName == DatePicker.FormatProperty.PropertyName)
+ {
UpdateDateFromModel(true);
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == DatePicker.MinimumDateProperty.PropertyName)
UpdateMinimumDate();
else if (e.PropertyName == DatePicker.MaximumDateProperty.PropertyName)
UpdateMaximumDate();
+ else if (e.PropertyName == DatePicker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == DatePicker.TextColorProperty.PropertyName || e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
UpdateTextColor();
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateFlowDirection();
- else if (e.PropertyName == DatePicker.FontAttributesProperty.PropertyName || e.PropertyName == DatePicker.FontFamilyProperty.PropertyName || e.PropertyName == DatePicker.FontSizeProperty.PropertyName)
+ else if (e.PropertyName == DatePicker.FontAttributesProperty.PropertyName ||
+ e.PropertyName == DatePicker.FontFamilyProperty.PropertyName || e.PropertyName == DatePicker.FontSizeProperty.PropertyName)
+ {
UpdateFont();
+ }
}
void HandleValueChanged(object sender, EventArgs e)
Control.Font = Element.ToUIFont();
}
+ void UpdateCharacterSpacing()
+ {
+ Control.AttributedText = Control.AttributedText.AddCharacterSpacing(Control.Text, Element.CharacterSpacing);
+ }
void UpdateMaximumDate()
{
_picker.MaximumDate = Element.MaximumDate.ToNSDate();
{
_placeholderLabel.Text = Element.Placeholder;
}
-
+
+ protected internal override void UpdateCharacterSpacing()
+ {
+ TextView.AttributedText = TextView.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+ _placeholderLabel.AttributedText = _placeholderLabel.AttributedText.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
+ }
+
protected internal override void UpdatePlaceholderColor()
{
Color placeholderColor = Element.PlaceholderColor;
);
_placeholderLabel.TranslatesAutoresizingMaskIntoConstraints = false;
+ _placeholderLabel.AttributedText = _placeholderLabel.AttributedText.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
Control.AddConstraints(hConstraints);
Control.AddConstraints(vConstraints);
UpdatePlaceholderColor();
UpdateTextColor();
UpdateText();
+ UpdateCharacterSpacing();
UpdateKeyboard();
UpdateEditable();
UpdateTextAlignment();
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Editor.TextProperty.PropertyName)
+ {
UpdateText();
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == Xamarin.Forms.InputView.KeyboardProperty.PropertyName)
UpdateKeyboard();
else if (e.PropertyName == Xamarin.Forms.InputView.IsSpellCheckEnabledProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == Editor.FontSizeProperty.PropertyName)
UpdateFont();
+ else if (e.PropertyName == Editor.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateTextAlignment();
else if (e.PropertyName == Xamarin.Forms.InputView.MaxLengthProperty.PropertyName)
UpdateMaxLength();
else if (e.PropertyName == Editor.PlaceholderProperty.PropertyName)
+ {
UpdatePlaceholderText();
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == Editor.PlaceholderColorProperty.PropertyName)
UpdatePlaceholderColor();
else if (e.PropertyName == Editor.AutoSizeProperty.PropertyName)
protected internal abstract void UpdatePlaceholderText();
protected internal abstract void UpdatePlaceholderColor();
-
+ protected internal abstract void UpdateCharacterSpacing();
void UpdateTextAlignment()
{
UpdatePlaceholder();
UpdatePassword();
UpdateText();
+ UpdateCharacterSpacing();
UpdateColor();
UpdateKeyboard();
UpdateAlignment();
else if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
UpdatePassword();
else if (e.PropertyName == Entry.TextProperty.PropertyName)
+ {
UpdateText();
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
UpdateColor();
+ else if (e.PropertyName == Entry.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Xamarin.Forms.InputView.KeyboardProperty.PropertyName)
UpdateKeyboard();
else if (e.PropertyName == Xamarin.Forms.InputView.IsSpellCheckEnabledProperty.PropertyName)
var color = targetColor.IsDefault ? _defaultPlaceholderColor : targetColor;
Control.AttributedPlaceholder = formatted.ToAttributed(Element, color);
}
+
+ Control.AttributedPlaceholder = Control.AttributedPlaceholder.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
}
void UpdateText()
Control.Text = Element.Text;
}
+ void UpdateCharacterSpacing()
+ {
+ Control.AttributedText = Control.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+ Control.AttributedPlaceholder = Control.AttributedPlaceholder.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
+ }
+
void UpdateMaxLength()
{
var currentControlText = Control.Text;
public static class FormattedStringExtensions
{
public static NSAttributedString ToAttributed(this Span span, Font defaultFont, Color defaultForegroundColor)
- {
+ {
if (span == null)
return null;
-
+
#pragma warning disable 0618 //retaining legacy call to obsolete code
var font = span.Font != Font.Default ? span.Font : defaultFont;
#pragma warning restore 0618
fgcolor = Color.Black; // as defined by apple docs
#if __MOBILE__
- return new NSAttributedString(span.Text, font == Font.Default ? null : font.ToUIFont(), fgcolor.ToUIColor(), span.BackgroundColor.ToUIColor());
+ return new NSAttributedString(span.Text, font == Font.Default ? null : font.ToUIFont(), fgcolor.ToUIColor(),
+ span.BackgroundColor.ToUIColor(), kerning: (float)span.CharacterSpacing);
#else
return new NSAttributedString(span.Text, font == Font.Default ? null : font.ToNSFont(), fgcolor.ToNSColor(),
- span.BackgroundColor.ToNSColor());
+ span.BackgroundColor.ToNSColor(), kerningAdjustment: (float)span.CharacterSpacing);
#endif
}
hasUnderline = (textDecorations & TextDecorations.Underline) != 0;
hasStrikethrough = (textDecorations & TextDecorations.Strikethrough) != 0;
}
-
+#if __MOBILE__
var attrString = new NSAttributedString(text, targetFont, spanFgColor, spanBgColor,
underlineStyle: hasUnderline ? NSUnderlineStyle.Single : NSUnderlineStyle.None,
- strikethroughStyle: hasStrikethrough ? NSUnderlineStyle.Single : NSUnderlineStyle.None, paragraphStyle: style);
+ strikethroughStyle: hasStrikethrough ? NSUnderlineStyle.Single : NSUnderlineStyle.None, paragraphStyle: style, kerning: (float)span.CharacterSpacing);
+#else
+ var attrString = new NSAttributedString(text, targetFont, spanFgColor, spanBgColor,
+ underlineStyle: hasUnderline ? NSUnderlineStyle.Single : NSUnderlineStyle.None,
+ strikethroughStyle: hasStrikethrough ? NSUnderlineStyle.Single : NSUnderlineStyle.None, paragraphStyle: style, kerningAdjustment: (float)span.CharacterSpacing);
+#endif
return attrString;
}
UpdateTextColor();
UpdateFont();
UpdateMaxLines();
+ UpdateCharacterSpacing();
UpdatePadding();
}
{
UpdateText();
UpdateTextDecorations();
+ UpdateCharacterSpacing();
}
+ else if (e.PropertyName == Label.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Label.TextDecorationsProperty.PropertyName)
UpdateTextDecorations();
else if (e.PropertyName == Label.FormattedTextProperty.PropertyName)
newAttributedText.AddAttribute(underlineStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);
#if __MOBILE__
- Control.AttributedText = newAttributedText;
+
+ Control.AttributedText = newAttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
#else
Control.AttributedStringValue = newAttributedText;
#endif
#endif
}
+ void UpdateCharacterSpacing()
+ {
+#if __MOBILE__
+ Control.AttributedText = Control.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+#endif
+ }
+
void UpdateText()
{
_formatted = Element.FormattedText;
UpdatePickerSelectedIndex(0);
UpdatePickerFromModel(s);
entry.ResignFirstResponder();
+ UpdateCharacterSpacing();
});
toolbar.SetItems(new[] { spacer, doneButton }, false);
UpdateFont();
UpdatePicker();
UpdateTextColor();
+ UpdateCharacterSpacing();
((INotifyCollectionChanged)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;
}
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Picker.TitleProperty.PropertyName || e.PropertyName == Picker.TitleColorProperty.PropertyName)
+ {
UpdatePicker();
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == Picker.SelectedIndexProperty.PropertyName)
+ {
UpdatePicker();
+ UpdateCharacterSpacing();
+ }
+ else if (e.PropertyName == Picker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == Picker.TextColorProperty.PropertyName || e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
UpdateTextColor();
- else if (e.PropertyName == Picker.FontAttributesProperty.PropertyName || e.PropertyName == Picker.FontFamilyProperty.PropertyName || e.PropertyName == Picker.FontSizeProperty.PropertyName)
+ else if (e.PropertyName == Picker.FontAttributesProperty.PropertyName || e.PropertyName == Picker.FontFamilyProperty.PropertyName ||
+ e.PropertyName == Picker.FontSizeProperty.PropertyName)
+ {
UpdateFont();
+ }
}
void OnEditing(object sender, EventArgs eventArgs)
void RowsCollectionChanged(object sender, EventArgs e)
{
UpdatePicker();
+ UpdateCharacterSpacing();
}
- protected internal virtual void UpdateFont()
+ protected void UpdateCharacterSpacing()
+ {
+ Control.AttributedText = Control.AttributedText.AddCharacterSpacing(Control.Text, Element.CharacterSpacing);
+ Control.AttributedPlaceholder = Control.AttributedPlaceholder.AddCharacterSpacing(Element.Title, Element.CharacterSpacing);
+ }
+
+ protected internal virtual void UpdateFont()
{
Control.Font = Element.ToUIFont();
}
var color = targetColor.IsDefault ? _defaultPlaceholderColor : targetColor;
Control.AttributedPlaceholder = formatted.ToAttributed(Element, color);
}
+
+ Control.AttributedPlaceholder = Control.AttributedPlaceholder.AddCharacterSpacing(Element.Title, Element.CharacterSpacing);
}
return;
UpdatePickerSelectedIndex(selectedIndex);
+ UpdateCharacterSpacing();
}
void UpdatePickerFromModel(PickerSource s)
UpdateCancelButton();
UpdateAlignment();
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdateMaxLength();
UpdateKeyboard();
}
}
else if (e.PropertyName == SearchBar.TextColorProperty.PropertyName)
UpdateTextColor();
+ else if (e.PropertyName == SearchBar.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
else if (e.PropertyName == SearchBar.TextProperty.PropertyName)
+ {
UpdateText();
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == SearchBar.CancelButtonColorProperty.PropertyName)
UpdateCancelButton();
else if (e.PropertyName == SearchBar.FontAttributesProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == SearchBar.FontFamilyProperty.PropertyName)
+ {
UpdateFont();
+ }
else if (e.PropertyName == SearchBar.FontSizeProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == SearchBar.HorizontalTextAlignmentProperty.PropertyName)
UpdateOnTextChanged();
}
+ void UpdateCharacterSpacing()
+ {
+ _textField = _textField ?? Control.FindDescendantView<UITextField>();
+ if (_textField == null)
+ return;
+ _textField.AttributedText = _textField.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+ _textField.AttributedPlaceholder = _textField.AttributedPlaceholder.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
+ }
+
void UpdateAlignment()
{
_textField = _textField ?? Control.FindDescendantView<UITextField>();
? targetColor : ColorExtensions.SeventyPercentGrey.ToColor();
_textField.AttributedPlaceholder = formatted.ToAttributed(Element, color);
+ _textField.AttributedPlaceholder.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
+
}
else
{
_textField.AttributedPlaceholder = formatted.ToAttributed(Element, targetColor.IsDefault
? ColorExtensions.SeventyPercentGrey.ToColor() : targetColor);
+ _textField.AttributedPlaceholder.AddCharacterSpacing(Element.Placeholder, Element.CharacterSpacing);
}
}
UpdateFont();
UpdateTime();
UpdateTextColor();
+ UpdateCharacterSpacing();
UpdateFlowDirection();
}
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == TimePicker.TimeProperty.PropertyName || e.PropertyName == TimePicker.FormatProperty.PropertyName)
+ {
UpdateTime();
+ UpdateCharacterSpacing();
+ }
else if (e.PropertyName == TimePicker.TextColorProperty.PropertyName || e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
UpdateTextColor();
- else if (e.PropertyName == TimePicker.FontAttributesProperty.PropertyName || e.PropertyName == TimePicker.FontFamilyProperty.PropertyName || e.PropertyName == TimePicker.FontSizeProperty.PropertyName)
+ else if (e.PropertyName == TimePicker.CharacterSpacingProperty.PropertyName)
+ UpdateCharacterSpacing();
+ else if (e.PropertyName == TimePicker.FontAttributesProperty.PropertyName ||
+ e.PropertyName == TimePicker.FontFamilyProperty.PropertyName || e.PropertyName == TimePicker.FontSizeProperty.PropertyName)
UpdateFont();
else if (e.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateFlowDirection();
Control.Text = Control.Text;
}
+ void UpdateCharacterSpacing()
+ {
+ Control.AttributedText = Control.AttributedText.AddCharacterSpacing(Control.Text, Element.CharacterSpacing);
+ }
+
void UpdateTime()
{
_picker.Date = new DateTime(1, 1, 1).Add(Element.Time).ToNSDate();