[iOS] Use UIButtonType.System for Button and utilize UIButton.Appearance (#554)
authoradrianknight89 <adrianknight89@outlook.com>
Mon, 20 Mar 2017 15:53:54 +0000 (10:53 -0500)
committerRui Marinho <me@ruimarinho.net>
Mon, 20 Mar 2017 15:53:54 +0000 (15:53 +0000)
* Change button style and use UIButton appearance

* added sample code

* change references

* setting other properties

* add comment

* refactor proxy setter

* made control states array static

* remove category declaration

* changes

* add sample code

* changes

* Fix identation

* Update ButtonRenderer.cs

Xamarin.Forms.ControlGallery.iOS/AppDelegate.cs
Xamarin.Forms.ControlGallery.iOS/CustomRenderer40251.cs [new file with mode: 0644]
Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40251.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Platform.iOS/Renderers/ButtonRenderer.cs

index d310773..1aed773 100644 (file)
@@ -205,7 +205,7 @@ namespace Xamarin.Forms.ControlGallery.iOS
                        sl?.Children.Add(uilabel);
 
                        // Create and add a native Button 
-                       var uibutton = new UIButton(UIButtonType.RoundedRect);
+                       var uibutton = new UIButton(UIButtonType.System);
                        uibutton.SetTitle("Toggle Text Amount", UIControlState.Normal);
                        uibutton.Font = UIFont.FromName("Helvetica", 14f);
 
@@ -304,7 +304,7 @@ namespace Xamarin.Forms.ControlGallery.iOS
                                Text = "DefaultText"
                        };
 
-                       var uibuttonColor = new UIButton(UIButtonType.RoundedRect);
+                       var uibuttonColor = new UIButton(UIButtonType.System);
                        uibuttonColor.SetTitle("Toggle Text Color Binding", UIControlState.Normal);
                        uibuttonColor.Font = UIFont.FromName("Helvetica", 14f);
                        uibuttonColor.TouchUpInside += (sender, args) => uilabel.TextColor = UIColor.Blue;
@@ -347,7 +347,7 @@ namespace Xamarin.Forms.ControlGallery.iOS
                public void StartPressed40911()
                {
                        var loginViewController = new UIViewController { View = { BackgroundColor = UIColor.White } };
-                       var button = UIButton.FromType(UIButtonType.RoundedRect);
+                       var button = UIButton.FromType(UIButtonType.System);
                        button.SetTitle("Login", UIControlState.Normal);
                        button.Frame = new CGRect(20, 100, 200, 44);
                        loginViewController.View.AddSubview(button);
diff --git a/Xamarin.Forms.ControlGallery.iOS/CustomRenderer40251.cs b/Xamarin.Forms.ControlGallery.iOS/CustomRenderer40251.cs
new file mode 100644 (file)
index 0000000..19ebbb7
--- /dev/null
@@ -0,0 +1,60 @@
+using UIKit;
+using Xamarin.Forms.Platform.iOS;
+using Xamarin.Forms;
+using System.Collections.Generic;
+using Xamarin.Forms.ControlGallery.iOS;
+using Xamarin.Forms.Controls.Issues;
+
+[assembly: ExportRenderer(typeof(Button), typeof(CustomRenderer40251))]
+namespace Xamarin.Forms.ControlGallery.iOS
+{
+       public class CustomRenderer40251 : ButtonRenderer
+       {
+               Dictionary<string, object> originalValues = new Dictionary<string, object>();
+
+               public CustomRenderer40251()
+               {
+                       if (TestPage40251.Arg == "TitleColor")
+                       {
+                               originalValues.Add("TitleColor", UIButton.Appearance.TitleColor(UIControlState.Normal));
+                               UIButton.Appearance.SetTitleColor(UIColor.Red, UIControlState.Normal);
+                       }
+                       else if (TestPage40251.Arg == "TitleShadowColor")
+                       {
+                               originalValues.Add("TitleShadowColor", UIButton.Appearance.TitleShadowColor(UIControlState.Normal));
+                               UIButton.Appearance.SetTitleShadowColor(UIColor.White, UIControlState.Normal);
+                       }
+                       else if (TestPage40251.Arg == "BackgroundImage")
+                       {
+                               originalValues.Add("BackgroundImage", UIButton.Appearance.BackgroundImageForState(UIControlState.Normal));
+                               UIButton.Appearance.SetBackgroundImage(new UIImage("Intranet-icon.png"), UIControlState.Normal);
+                       }
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
+               {
+                       base.OnElementChanged(e);
+
+                       if (e.NewElement != null)
+                       {
+                               if (Control != null)
+                                       Control.TitleShadowOffset = new CoreGraphics.CGSize(2, 2);
+                       }
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (disposing)
+                       {
+                               if (TestPage40251.Arg == "TitleColor")
+                                       UIButton.Appearance.SetTitleColor(originalValues["TitleColor"] as UIColor, UIControlState.Normal);
+                               else if (TestPage40251.Arg == "TitleShadowColor")
+                                       UIButton.Appearance.SetTitleShadowColor(originalValues["TitleShadowColor"] as UIColor, UIControlState.Normal);
+                               else if (TestPage40251.Arg == "BackgroundImage")
+                                       UIButton.Appearance.SetBackgroundImage(originalValues["BackgroundImage"] as UIImage, UIControlState.Normal);
+                       }
+
+                       base.Dispose(disposing);
+               }
+       }
+}
\ No newline at end of file
index a601b51..0810383 100644 (file)
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="BrokenNativeControl.cs" />
+    <Compile Include="CustomRenderer40251.cs" />
     <Compile Include="Main.cs" />
     <Compile Include="AppDelegate.cs" />
     <None Include="app.config" />
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40251.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40251.cs
new file mode 100644 (file)
index 0000000..64e9f66
--- /dev/null
@@ -0,0 +1,113 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System;
+
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Bugzilla, 40251, "Cannot style Buttons natively using UIButton.Appearance", PlatformAffected.iOS)]
+       public class Bugzilla40251 : TestNavigationPage // or TestMasterDetailPage, etc ...
+       {
+               protected override void Init()
+               {
+                       PushAsync(new LandingPage40251());
+               }
+       }
+
+       [Preserve(AllMembers = true)]
+       public class LandingPage40251 : ContentPage
+       {
+               public LandingPage40251()
+               {
+                       var stackLayout = new StackLayout
+                       {
+                               Orientation = StackOrientation.Vertical,
+                               Spacing = 20,
+                               VerticalOptions = LayoutOptions.Center
+                       };
+
+                       var label0 = new Label
+                       {
+                               Text = "Each label below will update UIButton.Appearance proxy. When you remove the page from the stack, the original value will be set again.",
+                               HorizontalTextAlignment = TextAlignment.Center
+                       };
+                       stackLayout.Children.Add(label0);
+
+                       var label1 = new Label
+                       {
+                               Text = "TitleColor",
+                               HorizontalTextAlignment = TextAlignment.Center
+                       };
+                       var t1 = new TapGestureRecognizer();
+                       t1.Tapped += T_Tapped;
+                       label1.GestureRecognizers.Add(t1);
+                       stackLayout.Children.Add(label1);
+
+                       var label2 = new Label
+                       {
+                               Text = "TitleShadowColor",
+                               HorizontalTextAlignment = TextAlignment.Center
+                       };
+                       var t2 = new TapGestureRecognizer();
+                       t2.Tapped += T_Tapped2;
+                       label2.GestureRecognizers.Add(t2);
+                       stackLayout.Children.Add(label2);
+
+                       var label3 = new Label
+                       {
+                               Text = "BackgroundImage",
+                               HorizontalTextAlignment = TextAlignment.Center
+                       };
+                       var t3 = new TapGestureRecognizer();
+                       t3.Tapped += T_Tapped3;
+                       label3.GestureRecognizers.Add(t3);
+                       stackLayout.Children.Add(label3);
+
+                       Content = stackLayout;
+               }
+
+               private async void T_Tapped(object sender, EventArgs e)
+               {
+                       await Navigation.PushAsync(new TestPage40251("TitleColor"));
+               }
+
+               private async void T_Tapped2(object sender, EventArgs e)
+               {
+                       await Navigation.PushAsync(new TestPage40251("TitleShadowColor"));
+               }
+
+               private async void T_Tapped3(object sender, EventArgs e)
+               {
+                       await Navigation.PushAsync(new TestPage40251("BackgroundImage"));
+               }
+       }
+
+       [Preserve(AllMembers = true)]
+       public class TestPage40251 : ContentPage
+       {
+               public static string Arg;
+
+               public TestPage40251(string arg)
+               {
+                       Arg = arg;
+
+                       Content = new ContentView
+                       {
+                               Content = new Button
+                               {
+                                       HorizontalOptions = LayoutOptions.Center,
+                                       VerticalOptions = LayoutOptions.Center,
+                                       Text = "Button",
+                                       BackgroundColor = Color.Black,
+                                       WidthRequest = 250,
+                                       HeightRequest = 50
+                               }
+                       };
+               }
+       }
+}
\ No newline at end of file
index 23fc538..d8b688d 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla40173.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla39821.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla40185.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Bugzilla40251.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla40333.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla31806.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla40408.cs" />
index dbdcb24..dd25e63 100644 (file)
@@ -23,6 +23,8 @@ namespace Xamarin.Forms.Platform.iOS
                // but under iOS that suggestion won't work
                readonly nfloat _minimumButtonHeight = 44; // Apple docs
 
+               static readonly UIControlState[] s_controlStates = { UIControlState.Normal, UIControlState.Highlighted, UIControlState.Disabled };
+
                public override SizeF SizeThatFits(SizeF size)
                {
                        var result = base.SizeThatFits(size);
@@ -54,10 +56,12 @@ namespace Xamarin.Forms.Platform.iOS
                        {
                                if (Control == null)
                                {
-                                       SetNativeControl(new UIButton(UIButtonType.RoundedRect));
+                                       SetNativeControl(new UIButton(UIButtonType.System));
 
                                        Debug.Assert(Control != null, "Control != null");
 
+                                       SetControlPropertiesFromProxy();
+
                                        _buttonTextColorDefaultNormal = Control.TitleColor(UIControlState.Normal);
                                        _buttonTextColorDefaultHighlighted = Control.TitleColor(UIControlState.Highlighted);
                                        _buttonTextColorDefaultDisabled = Control.TitleColor(UIControlState.Disabled);
@@ -89,7 +93,7 @@ namespace Xamarin.Forms.Platform.iOS
                        else if (e.PropertyName == Button.ImageProperty.PropertyName)
                                UpdateImage();
                }
-
+    
                protected override void SetAccessibilityLabel()
                {
                        // If we have not specified an AccessibilityLabel and the AccessibiltyLabel is current bound to the Title,
@@ -104,6 +108,16 @@ namespace Xamarin.Forms.Platform.iOS
 
                        base.SetAccessibilityLabel();
                }
+               
+               void SetControlPropertiesFromProxy()
+               {
+                       foreach (UIControlState uiControlState in s_controlStates)
+                       {
+                               Control.SetTitleColor(UIButton.Appearance.TitleColor(uiControlState), uiControlState); // if new values are null, old values are preserved.
+                               Control.SetTitleShadowColor(UIButton.Appearance.TitleShadowColor(uiControlState), uiControlState);
+                               Control.SetBackgroundImage(UIButton.Appearance.BackgroundImageForState(uiControlState), uiControlState);
+                       }
+               }
 
                void OnButtonTouchUpInside(object sender, EventArgs eventArgs)
                {
@@ -198,9 +212,7 @@ namespace Xamarin.Forms.Platform.iOS
                void ClearEdgeInsets(UIButton button)
                {
                        if (button == null)
-                       {
                                return;
-                       }
 
                        Control.ImageEdgeInsets = new UIEdgeInsets(0, 0, 0, 0);
                        Control.TitleEdgeInsets = new UIEdgeInsets(0, 0, 0, 0);
@@ -210,9 +222,7 @@ namespace Xamarin.Forms.Platform.iOS
                void ComputeEdgeInsets(UIButton button, Button.ButtonContentLayout layout)
                {
                        if (button?.ImageView?.Image == null || string.IsNullOrEmpty(button.TitleLabel?.Text))
-                       {
                                return;
-                       }
 
                        var position = layout.Position;
                        var spacing = (nfloat)(layout.Spacing / 2);
@@ -264,4 +274,4 @@ namespace Xamarin.Forms.Platform.iOS
                        button.TitleEdgeInsets = new UIEdgeInsets(titleVertOffset, -horizontalTitleOffset, -titleVertOffset, horizontalTitleOffset);
                }
        }
-}
\ No newline at end of file
+}