diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/RadioButtonGalleries/ContentProperties.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/RadioButtonGalleries/ContentProperties.xaml
index 5df45beb7487..f0e2f9e00ae6 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/RadioButtonGalleries/ContentProperties.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/RadioButtonGalleries/ContentProperties.xaml
@@ -43,6 +43,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
diff --git a/src/Controls/src/Core/HandlerImpl/RadioButton/RadioButton.Impl.cs b/src/Controls/src/Core/HandlerImpl/RadioButton/RadioButton.Impl.cs
index 4f3f124e1eb7..68dd3a7ec380 100644
--- a/src/Controls/src/Core/HandlerImpl/RadioButton/RadioButton.Impl.cs
+++ b/src/Controls/src/Core/HandlerImpl/RadioButton/RadioButton.Impl.cs
@@ -19,5 +19,23 @@ public partial class RadioButton : IRadioButton
Color IButtonStroke.StrokeColor => (Color)GetValue(BorderColorProperty);
int IButtonStroke.CornerRadius => (int)GetValue(CornerRadiusProperty);
+
+ private protected override Semantics UpdateSemantics()
+ {
+ var semantics = base.UpdateSemantics();
+
+ if (ControlTemplate != null)
+ {
+ string contentAsString = ContentAsString();
+
+ if (!string.IsNullOrWhiteSpace(contentAsString) && string.IsNullOrWhiteSpace(semantics?.Description))
+ {
+ semantics ??= new Semantics();
+ semantics.Description = contentAsString;
+ }
+ }
+
+ return semantics;
+ }
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs b/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs
index 4c130bf0a313..0199eb934f4f 100644
--- a/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs
+++ b/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Impl.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Maui.Controls
///
public partial class VisualElement : IView
{
- Semantics _semantics;
+ Semantics? _semantics;
bool _isLoadedFired;
EventHandler? _loaded;
EventHandler? _unloaded;
@@ -163,28 +163,23 @@ bool IView.IsFocused
Visibility IView.Visibility => IsVisible.ToVisibility();
- Semantics IView.Semantics
- {
- get
- {
- UpdateSemantics();
- return _semantics;
- }
- }
+ Semantics? IView.Semantics => UpdateSemantics();
- void UpdateSemantics()
+ private protected virtual Semantics? UpdateSemantics()
{
if (!this.IsSet(SemanticProperties.HintProperty) &&
!this.IsSet(SemanticProperties.DescriptionProperty) &&
!this.IsSet(SemanticProperties.HeadingLevelProperty))
{
- return;
+ _semantics = null;
+ return _semantics;
}
_semantics ??= new Semantics();
_semantics.Description = SemanticProperties.GetDescription(this);
_semantics.HeadingLevel = SemanticProperties.GetHeadingLevel(this);
_semantics.Hint = SemanticProperties.GetHint(this);
+ return _semantics;
}
static double EnsurePositive(double value)
diff --git a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.iOS.cs b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.iOS.cs
index e94e21deb617..fc4fc8dccc9a 100644
--- a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.iOS.cs
+++ b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.iOS.cs
@@ -9,11 +9,7 @@ protected override ContentView CreatePlatformView()
_ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} must be set to create a {nameof(ContentView)}");
_ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} cannot be null");
- return new ContentView
- {
- CrossPlatformMeasure = VirtualView.CrossPlatformMeasure,
- CrossPlatformArrange = VirtualView.CrossPlatformArrange
- };
+ return new SemanticSwitchContentView(VirtualView);
}
public override void SetVirtualView(IView view)
@@ -45,8 +41,13 @@ public static void MapContent(IRadioButtonHandler handler, IContentView page)
UpdateContent(handler);
}
- [MissingMapper]
- public static void MapIsChecked(IRadioButtonHandler handler, IRadioButton radioButton) { }
+ public static void MapIsChecked(IRadioButtonHandler handler, IRadioButton radioButton)
+ {
+ if (radioButton.IsChecked)
+ handler.PlatformView.AccessibilityValue = "1";
+ else
+ handler.PlatformView.AccessibilityValue = "0";
+ }
[MissingMapper]
public static void MapTextColor(IRadioButtonHandler handler, ITextStyle textStyle) { }
diff --git a/src/Core/src/Platform/iOS/SemanticSwitchContentView.cs b/src/Core/src/Platform/iOS/SemanticSwitchContentView.cs
new file mode 100644
index 000000000000..5205abc74972
--- /dev/null
+++ b/src/Core/src/Platform/iOS/SemanticSwitchContentView.cs
@@ -0,0 +1,42 @@
+using System;
+using CoreGraphics;
+using Microsoft.Maui.Graphics;
+using ObjCRuntime;
+using UIKit;
+
+namespace Microsoft.Maui.Platform;
+
+// This class should remain internal until further refactored.
+// It is currently being used only for RadioButton accessibility on iOS.
+internal class SemanticSwitchContentView : ContentView
+{
+ UIAccessibilityTrait _accessibilityTraits;
+
+ internal SemanticSwitchContentView(IContentView virtualView)
+ {
+ CrossPlatformMeasure = virtualView.CrossPlatformMeasure;
+ CrossPlatformArrange = virtualView.CrossPlatformArrange;
+ IsAccessibilityElement = true;
+ }
+
+ static UIKit.UIAccessibilityTrait? s_switchAccessibilityTraits;
+ UIKit.UIAccessibilityTrait SwitchAccessibilityTraits
+ {
+ get
+ {
+ if (s_switchAccessibilityTraits == null ||
+ s_switchAccessibilityTraits == UIKit.UIAccessibilityTrait.None)
+ {
+ s_switchAccessibilityTraits = new UIKit.UISwitch().AccessibilityTraits;
+ }
+
+ return s_switchAccessibilityTraits ?? UIKit.UIAccessibilityTrait.None;
+ }
+ }
+
+ public override UIAccessibilityTrait AccessibilityTraits
+ {
+ get => _accessibilityTraits |= SwitchAccessibilityTraits;
+ set => _accessibilityTraits = value | SwitchAccessibilityTraits;
+ }
+}
\ No newline at end of file