Friday, February 9, 2018

How can I change the colors of a stepper for iOS and Android?

Leave a Comment

My code uses a stepper which looks like this:

Stepper control :

Does anyone know how I could change the color Blue to Red for the iOS and Android versions of the stepper by setting the new color in XAML? Note this last need was added to the text of the bounty. Thanks

4 Answers

Answers 1

This can be done using Effects.

Code

I've created a sample app here: https://github.com/brminnick/CustomStepper

Consuming the Effects in XAML

<?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="CustomStepper.StepperPage"     xmlns:local="clr-namespace:CustomStepper">      <ContentPage.Content>         <StackLayout              HorizontalOptions="Center"             VerticalOptions="Center">              <local:RedStepper/>             <Stepper                 local:StepperColorEffect.Color="Red"/>          </StackLayout>     </ContentPage.Content> </ContentPage> 

Stepper Color Effect

using System.Linq;  using Xamarin.Forms;  namespace CustomStepper {     public static class StepperColorEffect     {         public static readonly BindableProperty ColorProperty =             BindableProperty.CreateAttached(nameof(Color),                 typeof(Color),                 typeof(Stepper),                 Color.Gray,                 propertyChanged: OnStepperColorChanged);          public static Color GetColor(BindableObject view) => (Color)view.GetValue(ColorProperty);          public static void SetColor(BindableObject view, Color value) => view.SetValue(ColorProperty, value);          static void OnStepperColorChanged(BindableObject bindable, object oldValue, object newValue) => UpdateEffect(bindable);          static void UpdateEffect(BindableObject bindable)         {             switch (bindable)             {                 case Stepper stepper:                     RemoveEffect(stepper);                     stepper.Effects.Add(new StepperColorRoutingEffect());                     break;             }         }          static void RemoveEffect(Stepper entry)         {             var effectToRemoveList = entry.Effects.Where(e => e is StepperColorRoutingEffect).ToList();              foreach (var entryReturnTypeEffect in effectToRemoveList)                 entry.Effects.Remove(entryReturnTypeEffect);         }     }      class StepperColorRoutingEffect : RoutingEffect     {         public StepperColorRoutingEffect() : base("CustomStepper.StepperColorEffect")         {         }     } } 

iOS PlatformEffect

using UIKit;  using Xamarin.Forms; using Xamarin.Forms.Platform.iOS;  using CustomStepper.iOS;  [assembly: ResolutionGroupName("CustomStepper")] [assembly: ExportEffect(typeof(StepperColorEffect), nameof(StepperColorEffect))] namespace CustomStepper.iOS {     public class StepperColorEffect : PlatformEffect     {         protected override void OnAttached()         {             if (Element is Stepper element && Control is UIStepper control)                 control.TintColor = CustomStepper.StepperColorEffect.GetColor(element).ToUIColor();         }          protected override void OnDetached()         {             if (Element is Stepper element && Control is UIStepper control)                 control.TintColor = UIColor.Blue;         }     } } 

Android PlatformEffect

using Android.Widget; using Android.Graphics;  using Xamarin.Forms; using Xamarin.Forms.Platform.Android;  using CustomStepper.Droid;  [assembly: ResolutionGroupName("CustomStepper")] [assembly: ExportEffect(typeof(StepperColorEffect), nameof(StepperColorEffect))] namespace CustomStepper.Droid {     public class StepperColorEffect : PlatformEffect     {         protected override void OnAttached()         {             if (Element is Stepper element && Control is LinearLayout control)             {                 control.GetChildAt(0).Background.SetColorFilter(CustomStepper.StepperColorEffect.GetColor(element).ToAndroid(), PorterDuff.Mode.Multiply);                 control.GetChildAt(1).Background.SetColorFilter(CustomStepper.StepperColorEffect.GetColor(element).ToAndroid(), PorterDuff.Mode.Multiply);             }         }          protected override void OnDetached()         {             if (Element is Stepper element && Control is LinearLayout control)             {                 control.GetChildAt(0).Background.SetColorFilter(Xamarin.Forms.Color.Gray.ToAndroid(), PorterDuff.Mode.Multiply);                 control.GetChildAt(1).Background.SetColorFilter(Xamarin.Forms.Color.Gray.ToAndroid(), PorterDuff.Mode.Multiply);             }         }     } } 

Screenshots

Android

enter image description here

iOS

enter image description here

Answers 2

How can I change the colors of a stepper for iOS and Android?

In your Xamarin.Android project, you could create a custom vector drawable and use it as a background to achieve the same appearance as the picture you have post above.

Place the button_selector.xml and button_border.xml file in your Android Resources\drawable folder:

button_selector.xml

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android">   <item android:drawable="@color/colorAccent" android:state_pressed="true"/>   <item android:drawable="@color/colorPrimaryDark" android:state_focused="true"/>   <item android:drawable="@drawable/button_border"/> </selector> 

button_border.xml:

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"        android:shape="rectangle" >    <solid android:color="#00FFFFFF" />   <corners android:radius="5dp" />   <stroke     android:width="2dp"     android:color="#FFFFFF" />  </shape> 

In your ExtStepperRenderer:

protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e) {     base.OnElementChanged(e);     MyStepper s = Element as MyStepper;      if (Control != null)     {         var button = Control.GetChildAt(0) as Android.Widget.Button;         button.SetTextColor(s.MyColor.ToAndroid());         button.SetBackground(ResourcesCompat.GetDrawable(Resources, Resource.Drawable.button_selector, null));         button.Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);          var button2 = Control.GetChildAt(1) as Android.Widget.Button;         button2.SetTextColor(s.MyColor.ToAndroid());         button2.SetBackground(ResourcesCompat.GetDrawable(Resources, Resource.Drawable.button_selector, null));         button2.Background.SetColorFilter(s.MyColor.ToAndroid(), PorterDuff.Mode.Multiply);     } } 

Effect on Android device:

enter image description here

Answers 3

You will need to create a custom renderer. Looking at the source code, the native control for the Stepper on iOS is UIStepper, and on Android it is actually a horizontal LinearLayout with two buttons. So for Android, the custom renderer should update the background color of the buttons, and on iOS, they appear to be icons, so try changing the TintColor of the UIStepper.

Answers 4

I came up with a simple solution.

Common File:

using Xamarin.Forms;  namespace Japanese {     public class ExtStepper : Stepper     {          public static readonly BindableProperty ColorProperty =    BindableProperty.Create(nameof(Color),        typeof(Color), typeof(ExtStepper),        Color.Default);          public Color StepperColor         {             get { return (Color)GetValue(ColorProperty); }             set { SetValue(ColorProperty, value); }         }      } } 

iOS

using Xamarin.Forms; using Japanese; using Japanese.iOS; using Xamarin.Forms.Platform.iOS;  [assembly: ExportRenderer(typeof(ExtStepper), typeof(ExtStepperRenderer))] namespace Japanese.iOS {     public class ExtStepperRenderer : StepperRenderer     {         protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)         {             base.OnElementChanged(e);             ExtStepper s = Element as ExtStepper;              if (Control != null)                 Control.TintColor = s.StepperColor.ToUIColor();          }     } } 

Andoid

using Xamarin.Forms; using Xamarin.Forms.Platform.Android; using Japanese; using Japanese.Droid; using Android.Content; using Android.Graphics;  [assembly: ExportRenderer(typeof(ExtStepper), typeof(ExtStepperRenderer))] namespace Japanese.Droid {     public class ExtStepperRenderer : StepperRenderer     {         public ExtStepperRenderer(Context context) : base(context)         {         }          protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)         {             base.OnElementChanged(e);             ExtStepper s = Element as ExtStepper;              if (Control != null)             {                 Control.GetChildAt(0).Background.SetColorFilter(s.StepperColor.ToAndroid(), PorterDuff.Mode.Multiply);                 Control.GetChildAt(1).Background.SetColorFilter(s.StepperColor.ToAndroid(), PorterDuff.Mode.Multiply);             }           }     } } 

XAML

<local:ExtStepper StepperColor="Red" x:Name="rptStepper 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment