[macOS] Add character spacing to button and label (#8206)
authorOliver Brown <galaxiaguy@gmail.com>
Tue, 5 Nov 2019 14:53:33 +0000 (14:53 +0000)
committerRui Marinho <me@ruimarinho.net>
Tue, 5 Nov 2019 14:53:33 +0000 (14:53 +0000)
* Add character spacing extension method to macOS

* Add character spacing to label on macOS.

* Add character spacing for button on macOS

* Add color pickers to character spacing gallery to check everything works with colors.

* Make character spacing and text color work properly together on button and label on macOS.

Xamarin.Forms.Controls/GalleryPages/CharacterSpacingGallery.xaml
Xamarin.Forms.Controls/GalleryPages/CharacterSpacingGallery.xaml.cs
Xamarin.Forms.Platform.MacOS/Extensions/NSAttributedStringExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.MacOS/Renderers/ButtonRenderer.cs
Xamarin.Forms.Platform.MacOS/Xamarin.Forms.Platform.macOS.csproj
Xamarin.Forms.Platform.iOS/Renderers/LabelRenderer.cs

index 06167af..c866109 100644 (file)
@@ -2,7 +2,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">
+             x:Class="Xamarin.Forms.Controls.GalleryPages.CharacterSpacingGallery"
+             xmlns:controls="clr-namespace:Xamarin.Forms.Controls">
 
     <StackLayout>
         <Label>
@@ -16,6 +17,8 @@
         </Label>
         <Slider x:Name="slider" Minimum="-10" Maximum="10" Value="0" ValueChanged="Slider_OnValueChanged" MaximumTrackColor="Gray"
                 MinimumTrackColor="Gray"  Margin="20,0"/>
+        <controls:ColorPicker x:Name="textColorPicker" ColorPicked="ColorPicker_OnColorPicked" Title="Text color" />
+        <controls:ColorPicker x:Name="placeholderColorPicker" ColorPicked="ColorPicker_OnColorPicked" Title="Placeholder color" />
 
         <ScrollView>
             <StackLayout>
index 63a0283..5ff0d93 100644 (file)
@@ -15,6 +15,8 @@ namespace Xamarin.Forms.Controls.GalleryPages
                public CharacterSpacingGallery()
                {
                        InitializeComponent();
+                       textColorPicker.InitWithColor(Color.Red);
+                       placeholderColorPicker.InitWithColor(Color.BlueViolet);
                }
 
                void Slider_OnValueChanged(object sender, ValueChangedEventArgs e)
@@ -34,9 +36,37 @@ namespace Xamarin.Forms.Controls.GalleryPages
                        Span.CharacterSpacing = e.NewValue;
                }
 
+               void ColorPicker_OnColorPicked(object sender, ColorPickedEventArgs e)
+               {
+                       if (sender == textColorPicker)
+                       {
+                               Button.TextColor = e.Color;
+                               DatePicker.TextColor = e.Color;
+                               Editor.TextColor = e.Color;
+                               Entry.TextColor = e.Color;
+                               PlaceholderEntry.TextColor = e.Color;
+                               PlaceholderEditor.TextColor = e.Color;
+                               Label.TextColor = e.Color;
+                               Picker.TextColor = e.Color;
+                               SearchBar.TextColor = e.Color;
+                               PlaceholderSearchBar.TextColor = e.Color;
+                               TimePicker.TextColor = e.Color;
+                               Span.TextColor = e.Color;
+                       }
+                       else
+                       {
+                               PlaceholderEntry.PlaceholderColor = e.Color;
+                               PlaceholderEditor.PlaceholderColor = e.Color;
+                               PlaceholderSearchBar.PlaceholderColor = e.Color;
+
+                       }
+               }
+
                void ResetButtonClicked(object sender, EventArgs e)
                {
                        slider.Value = 0;
+                       textColorPicker.InitWithColor(Color.Red);
+                       placeholderColorPicker.InitWithColor(Color.BlueViolet);
                }
        }
 }
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.MacOS/Extensions/NSAttributedStringExtensions.cs b/Xamarin.Forms.Platform.MacOS/Extensions/NSAttributedStringExtensions.cs
new file mode 100644 (file)
index 0000000..68f1da7
--- /dev/null
@@ -0,0 +1,53 @@
+using AppKit;
+using Foundation;
+
+namespace Xamarin.Forms.Platform.MacOS
+{
+    internal static class NSAttributedStringExtensions
+    {
+        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
+                (
+                    NSStringAttributeKey.KerningAdjustment,
+                    NSObject.FromObject(characterSpacing), new NSRange(0, text.Length - 1)
+                );
+            }
+        }
+    }
+}
\ No newline at end of file
index ce524e3..d824ff4 100644 (file)
@@ -102,6 +102,7 @@ namespace Xamarin.Forms.Platform.MacOS
                                }
 
                                UpdateText();
+                               UpdateCharacterSpacing();
                                UpdateFont();
                                UpdateBorder();
                                UpdateImage();
@@ -127,6 +128,8 @@ namespace Xamarin.Forms.Platform.MacOS
                                UpdateImage();
                        else if (e.PropertyName == Button.PaddingProperty.PropertyName)
                                UpdatePadding();
+                       else if (e.PropertyName == Button.CharacterSpacingProperty.PropertyName)
+                               UpdateCharacterSpacing();
                }
 
                void OnButtonActivated(object sender, EventArgs eventArgs)
@@ -186,6 +189,7 @@ namespace Xamarin.Forms.Platform.MacOS
                        else
                        {
                                var textWithColor = new NSAttributedString(Element.Text ?? "", font: Element.Font.ToNSFont(), foregroundColor: color.ToNSColor(), paragraphStyle: new NSMutableParagraphStyle() { Alignment = NSTextAlignment.Center });
+                               textWithColor = textWithColor.AddCharacterSpacing(Element.Text ?? string.Empty, Element.CharacterSpacing);
                                Control.AttributedTitle = textWithColor;
                        }
                }
@@ -195,6 +199,11 @@ namespace Xamarin.Forms.Platform.MacOS
                        (Control as FormsNSButton)?.UpdatePadding(Element.Padding);
                }
 
+               void UpdateCharacterSpacing()
+               {
+                       Control.AttributedTitle = Control.AttributedTitle.AddCharacterSpacing(Element.Text ?? string.Empty, Element.CharacterSpacing);
+               }
+
                void HandleButtonPressed()
                {
                        Element?.SendPressed();
index ec7c51b..bc20e5e 100644 (file)
     <Compile Include="..\Xamarin.Forms.Platform.iOS\Extensions\FontExtensions.Shared.cs">
       <Link>Extensions\FontExtensions.Shared.cs</Link>
     </Compile>
+    <Compile Include="Extensions\NSAttributedStringExtensions.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Xamarin.Forms.Platform\Xamarin.Forms.Platform.csproj">
index d612562..3f5b784 100644 (file)
@@ -278,11 +278,10 @@ namespace Xamarin.Forms.Platform.MacOS
                        else
                                newAttributedText.AddAttribute(underlineStyleKey, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);
 
-#if __MOBILE__
-                       UpdateCharacterSpacing();
-#else
+#if !__MOBILE__
                        Control.AttributedStringValue = newAttributedText;
 #endif
+                       UpdateCharacterSpacing();
                        _perfectSizeValid = false;
                }
 
@@ -379,20 +378,24 @@ namespace Xamarin.Forms.Platform.MacOS
 
                void UpdateCharacterSpacing()
                {
-#if __MOBILE__
                        if (IsElementOrControlEmpty)
                                return;
 
                        if (Element?.TextType != TextType.Text)
                                return;
-
+#if __MOBILE__
                        var textAttr = Control.AttributedText.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
 
                        if (textAttr != null)
                                Control.AttributedText = textAttr;
-                               
-                       _perfectSizeValid = false;
+#else
+                       var textAttr = Control.AttributedStringValue.AddCharacterSpacing(Element.Text, Element.CharacterSpacing);
+
+                       if (textAttr != null)
+                               Control.AttributedStringValue = textAttr;
 #endif
+
+                       _perfectSizeValid = false;
                }
 
                void UpdateText()
@@ -510,7 +513,10 @@ namespace Xamarin.Forms.Platform.MacOS
 #if __MOBILE__
                        Control.TextColor = textColor.ToUIColor(ColorExtensions.Black);
 #else
-                       Control.TextColor = textColor.ToNSColor(ColorExtensions.Black);
+                       var alignment = Element.HorizontalTextAlignment.ToNativeTextAlignment(((IVisualElementController)Element).EffectiveFlowDirection);
+                       var textWithColor = new NSAttributedString(Element.Text ?? "", font: Element.ToNSFont(), foregroundColor: textColor.ToNSColor(), paragraphStyle: new NSMutableParagraphStyle() { Alignment = alignment });
+                       textWithColor = textWithColor.AddCharacterSpacing(Element.Text ?? string.Empty, Element.CharacterSpacing);
+                       Control.AttributedStringValue = textWithColor;
 #endif
                        UpdateLayout();
                }