Android分段控件色调修改及C#后端动态操作SegmentedControl问询
Hey there! Let's break down how to handle both selecting segments programmatically and customizing the color of your cross-platform SegmentedControl for iOS and Android.
1. Programmatically Selecting a Segment in C#
To enable programmatic selection, you'll need to add a bindable property to your SegmentedControl class to track the selected index (or selected option), then update the native platform controls to reflect this state.
Step 1: Add Selected Index/Option Bindable Properties
Extend your existing SegmentedControl class with these properties:
public class SegmentedControl : View, IViewContainer<SegmentedControlOption> { // ... Your existing code ... // Track selected index public static readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(nameof(SelectedIndex), typeof(int), typeof(SegmentedControl), -1, propertyChanged: OnSelectedIndexChanged); public int SelectedIndex { get => (int)GetValue(SelectedIndexProperty); set => SetValue(SelectedIndexProperty, value); } // Track selected option (optional, for direct option binding) public static readonly BindableProperty SelectedOptionProperty = BindableProperty.Create(nameof(SelectedOption), typeof(SegmentedControlOption), typeof(SegmentedControl), null, propertyChanged: OnSelectedOptionChanged); public SegmentedControlOption SelectedOption { get => (SegmentedControlOption)GetValue(SelectedOptionProperty); set => SetValue(SelectedOptionProperty, value); } // Handle index change private static void OnSelectedIndexChanged(BindableObject bindable, object oldValue, object newValue) { var control = (SegmentedControl)bindable; if (control.Children != null && control.SelectedIndex >= 0 && control.SelectedIndex < control.Children.Count) { control.OnSelectedIndexChanged((int)oldValue, (int)newValue); } } // Handle option change private static void OnSelectedOptionChanged(BindableObject bindable, object oldValue, object newValue) { var control = (SegmentedControl)bindable; if (newValue is SegmentedControlOption option) { var index = control.Children.IndexOf(option); if (index != -1 && control.SelectedIndex != index) { control.SelectedIndex = index; } } else { control.SelectedIndex = -1; } } // Event for external listeners public event EventHandler<SelectedIndexChangedEventArgs> SelectedIndexChanged; protected virtual void OnSelectedIndexChanged(int oldIndex, int newIndex) { SelectedIndexChanged?.Invoke(this, new SelectedIndexChangedEventArgs(oldIndex, newIndex)); } } // Helper event args class public class SelectedIndexChangedEventArgs : EventArgs { public int OldIndex { get; } public int NewIndex { get; } public SelectedIndexChangedEventArgs(int oldIndex, int newIndex) { OldIndex = oldIndex; NewIndex = newIndex; } }
Step 2: Update Native Renderers
You need to sync the selected index with the native platform controls:
iOS Renderer
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == SegmentedControl.SelectedIndexProperty.PropertyName) { var nativeControl = (UISegmentedControl)Control; var segmentedControl = (SegmentedControl)Element; if (segmentedControl.SelectedIndex >= 0 && segmentedControl.SelectedIndex < nativeControl.NumberOfSegments) { nativeControl.SelectedSegment = segmentedControl.SelectedIndex; } } }
Android Renderer
Assuming you're using a RadioGroup-based implementation:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == SegmentedControl.SelectedIndexProperty.PropertyName) { var segmentedControl = (SegmentedControl)Element; if (segmentedControl.SelectedIndex >= 0 && segmentedControl.SelectedIndex < Control.ChildCount) { var selectedButton = (RadioButton)Control.GetChildAt(segmentedControl.SelectedIndex); selectedButton.Checked = true; } } }
Step 3: Use Programmatic Selection
Now you can select segments in your C# code like this:
// Select the first segment (index 0) mySegmentedControl.SelectedIndex = 0; // Or select a specific option directly var targetOption = mySegmentedControl.Children.FirstOrDefault(o => o.Text == "Settings"); mySegmentedControl.SelectedOption = targetOption;
2. Customizing the Control's Color
You already started with the TintColorProperty—let's complete the implementation to apply this color to native controls.
Step 1: Finalize the TintColor Property
Update your existing property with change handling:
public static readonly BindableProperty TintColorProperty = BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(SegmentedControl), Colors.Blue, propertyChanged: OnTintColorChanged); public Color TintColor { get => (Color)GetValue(TintColorProperty); set => SetValue(TintColorProperty, value); } private static void OnTintColorChanged(BindableObject bindable, object oldValue, object newValue) { var control = (SegmentedControl)bindable; control.OnTintColorChanged((Color)oldValue, (Color)newValue); } protected virtual void OnTintColorChanged(Color oldColor, Color newColor) { // Optional: Trigger event if external code needs to react to color changes }
Step 2: Apply Color to Native Controls
iOS Renderer
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == SegmentedControl.TintColorProperty.PropertyName) { var nativeControl = (UISegmentedControl)Control; var segmentedControl = (SegmentedControl)Element; var uiColor = segmentedControl.TintColor.ToUIColor(); // Set tint color for selected segment border/text nativeControl.TintColor = uiColor; // Optional: Customize selected text color nativeControl.SetTitleTextAttributes(new UITextAttributes { TextColor = uiColor }, UIControlState.Selected); } }
Android Renderer
For a custom segmented control using RadioButtons:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == SegmentedControl.TintColorProperty.PropertyName) { var segmentedControl = (SegmentedControl)Element; var androidColor = segmentedControl.TintColor.ToAndroid(); for (int i = 0; i < Control.ChildCount; i++) { var button = (RadioButton)Control.GetChildAt(i); // Set text color for selected/unselected states button.SetTextColor(new ColorStateList( new int[][] { new int[] { Android.Resource.Attribute.StateChecked }, new int[0] }, new int[] { androidColor, Android.Graphics.Color.Gray } )); // Set rounded background for selected/unselected states var shape = new GradientDrawable(); shape.SetCornerRadius(8); // Adjust radius to match your design shape.SetColor(new ColorStateList( new int[][] { new int[] { Android.Resource.Attribute.StateChecked }, new int[0] }, new int[] { androidColor, Android.Graphics.Color.Transparent } )); button.Background = shape; } } }
Step 3: Modify Color Programmatically
Change the color in your C# code like this:
// Set to a solid color mySegmentedControl.TintColor = Colors.Orange; // Or use a hex color mySegmentedControl.TintColor = Color.FromHex("#2ECC71");
内容的提问来源于stack exchange,提问作者iamsophia

