@@ -855,6 +855,19 @@ void UnwireEvents()
855
855
}
856
856
857
857
UnWireLabelStyleEvents ( ) ;
858
+
859
+ #if ANDROID
860
+ // Unwire assistive label handler changed events
861
+ if ( _helperLabel != null )
862
+ {
863
+ _helperLabel . HandlerChanged -= OnAssistiveLabelHandlerChanged ;
864
+ }
865
+ if ( _errorLabel != null )
866
+ {
867
+ _errorLabel . HandlerChanged -= OnAssistiveLabelHandlerChanged ;
868
+ }
869
+ #endif
870
+ DisposeAssistiveLabels ( ) ;
858
871
}
859
872
860
873
/// <summary>
@@ -2077,46 +2090,9 @@ void DrawHintText(ICanvas canvas, RectF dirtyRect)
2077
2090
2078
2091
void DrawAssistiveText ( ICanvas canvas , RectF dirtyRect )
2079
2092
{
2080
- if ( HasError )
2081
- {
2082
- DrawErrorText ( canvas , dirtyRect ) ;
2083
- }
2084
- else
2085
- {
2086
- DrawHelperText ( canvas , dirtyRect ) ;
2087
- }
2088
-
2089
2093
DrawCounterText ( canvas , dirtyRect ) ;
2090
2094
}
2091
2095
2092
- void DrawHelperText ( ICanvas canvas , RectF dirtyRect )
2093
- {
2094
- if ( ShowHelperText && ! string . IsNullOrEmpty ( HelperText ) && HelperLabelStyle != null )
2095
- {
2096
- canvas . CanvasSaveState ( ) ;
2097
- UpdateHelperTextPosition ( ) ;
2098
- UpdateHelperTextColor ( ) ;
2099
-
2100
- canvas . DrawText ( HelperText , _helperTextRect , IsRTL ? HorizontalAlignment . Right : HorizontalAlignment . Left , VerticalAlignment . Top , _internalHelperLabelStyle ) ;
2101
-
2102
- canvas . CanvasRestoreState ( ) ;
2103
- }
2104
- }
2105
-
2106
- void DrawErrorText ( ICanvas canvas , RectF dirtyRect )
2107
- {
2108
- if ( ! string . IsNullOrEmpty ( ErrorText ) && ErrorLabelStyle != null )
2109
- {
2110
- canvas . CanvasSaveState ( ) ;
2111
- UpdateErrorTextPosition ( ) ;
2112
- UpdateErrorTextColor ( ) ;
2113
-
2114
- canvas . DrawText ( ErrorText , _errorTextRect , IsRTL ? HorizontalAlignment . Right : HorizontalAlignment . Left , VerticalAlignment . Top , _internalErrorLabelStyle ) ;
2115
-
2116
- canvas . CanvasRestoreState ( ) ;
2117
- }
2118
- }
2119
-
2120
2096
void DrawCounterText ( ICanvas canvas , RectF dirtyRect )
2121
2097
{
2122
2098
if ( ShowCharCount && ! string . IsNullOrEmpty ( _counterText ) && CounterLabelStyle != null )
@@ -2239,6 +2215,188 @@ void OnTranslateAnimationEnded(double value, bool isCompleted)
2239
2215
IsHintDownToUp = ! IsHintDownToUp ;
2240
2216
}
2241
2217
2218
+ /// <summary>
2219
+ /// Initializes the assistive labels (helper and error text labels).
2220
+ /// </summary>
2221
+ void InitializeAssistiveLabels ( )
2222
+ {
2223
+ if ( _helperLabel != null && Children . Contains ( _helperLabel ) )
2224
+ Remove ( _helperLabel ) ;
2225
+ if ( _errorLabel != null && Children . Contains ( _errorLabel ) )
2226
+ Remove ( _errorLabel ) ;
2227
+
2228
+ if ( _helperLabel == null )
2229
+ {
2230
+ _helperLabel = new Label
2231
+ {
2232
+ IsVisible = false ,
2233
+ LineBreakMode = LineBreakMode . WordWrap ,
2234
+ } ;
2235
+ }
2236
+
2237
+ if ( _errorLabel == null )
2238
+ {
2239
+ _errorLabel = new Label
2240
+ {
2241
+ IsVisible = false ,
2242
+ LineBreakMode = LineBreakMode . WordWrap ,
2243
+ } ;
2244
+ }
2245
+
2246
+ ConfigureAccessibilityForAssistiveLabels ( ) ;
2247
+
2248
+ Add ( _helperLabel ) ;
2249
+ Add ( _errorLabel ) ;
2250
+ }
2251
+
2252
+ /// <summary>
2253
+ /// Configures accessibility properties for assistive labels to ensure proper focus order on Android.
2254
+ /// </summary>
2255
+ void ConfigureAccessibilityForAssistiveLabels ( )
2256
+ {
2257
+ #if ANDROID
2258
+ // Configure helper label accessibility
2259
+ if ( _helperLabel != null )
2260
+ {
2261
+ UpdateLabelAccessibilityImportance ( _helperLabel , false ) ;
2262
+ _helperLabel . HandlerChanged += OnAssistiveLabelHandlerChanged ;
2263
+ }
2264
+
2265
+ // Configure error label accessibility
2266
+ if ( _errorLabel != null )
2267
+ {
2268
+ UpdateLabelAccessibilityImportance ( _errorLabel , false ) ;
2269
+ _errorLabel . HandlerChanged += OnAssistiveLabelHandlerChanged ;
2270
+ }
2271
+ #endif
2272
+ }
2273
+
2274
+ #if ANDROID
2275
+ /// <summary>
2276
+ /// Handles the HandlerChanged event for assistive labels to ensure proper accessibility setup.
2277
+ /// </summary>
2278
+ void OnAssistiveLabelHandlerChanged ( object ? sender , EventArgs e )
2279
+ {
2280
+ if ( sender is Label label )
2281
+ {
2282
+ bool isVisible = label . IsVisible && ! string . IsNullOrEmpty ( label . Text ) ;
2283
+ UpdateLabelAccessibilityImportance ( label , isVisible ) ;
2284
+ }
2285
+ }
2286
+
2287
+ /// <summary>
2288
+ /// Updates the accessibility importance of a label based on its visibility and content.
2289
+ /// This ensures proper focus order in TalkBack.
2290
+ /// </summary>
2291
+ /// <param name="label">The label to update</param>
2292
+ /// <param name="isVisible">Whether the label should be important for accessibility</param>
2293
+ void UpdateLabelAccessibilityImportance ( Label label , bool isVisible )
2294
+ {
2295
+ if ( label ? . Handler ? . PlatformView is Android . Views . View androidView )
2296
+ {
2297
+ if ( isVisible && ! string . IsNullOrEmpty ( label . Text ) )
2298
+ {
2299
+ androidView . ImportantForAccessibility = Android . Views . ImportantForAccessibility . Yes ;
2300
+ androidView . Focusable = true ;
2301
+ }
2302
+ else
2303
+ {
2304
+ androidView . ImportantForAccessibility = Android . Views . ImportantForAccessibility . No ;
2305
+ androidView . Focusable = false ;
2306
+ }
2307
+ }
2308
+ }
2309
+ #endif
2310
+
2311
+ /// <summary>
2312
+ /// Updates the assistive labels visibility and content.
2313
+ /// </summary>
2314
+ void UpdateAssistiveLabels ( )
2315
+ {
2316
+ // Initialize labels if not already created
2317
+ if ( _helperLabel == null || _errorLabel == null )
2318
+ {
2319
+ InitializeAssistiveLabels ( ) ;
2320
+ }
2321
+
2322
+ if ( _helperLabel != null )
2323
+ {
2324
+ if ( ShowHelperText && ! string . IsNullOrEmpty ( HelperText ) && ! HasError && ReserveSpaceForAssistiveLabels )
2325
+ {
2326
+ _helperLabel . Text = HelperText ;
2327
+ _helperLabel . IsVisible = true ;
2328
+ UpdateHelperTextPosition ( ) ;
2329
+ UpdateHelperTextColor ( ) ;
2330
+ ApplyLabelStyle ( _helperLabel , _internalHelperLabelStyle ) ;
2331
+ #if ANDROID
2332
+ UpdateLabelAccessibilityImportance ( _helperLabel , true ) ;
2333
+ #endif
2334
+ AbsoluteLayout . SetLayoutBounds ( _helperLabel , _helperTextRect ) ;
2335
+ }
2336
+ else
2337
+ {
2338
+ _helperLabel . IsVisible = false ;
2339
+ #if ANDROID
2340
+ UpdateLabelAccessibilityImportance ( _helperLabel , false ) ;
2341
+ #endif
2342
+ }
2343
+ }
2344
+
2345
+ if ( _errorLabel != null )
2346
+ {
2347
+ if ( HasError && ! string . IsNullOrEmpty ( ErrorText ) && ReserveSpaceForAssistiveLabels )
2348
+ {
2349
+ _errorLabel . Text = ErrorText ;
2350
+ _errorLabel . IsVisible = true ;
2351
+ UpdateErrorTextPosition ( ) ;
2352
+ UpdateErrorTextColor ( ) ;
2353
+ ApplyLabelStyle ( _errorLabel , _internalErrorLabelStyle ) ;
2354
+ #if ANDROID
2355
+ UpdateLabelAccessibilityImportance ( _errorLabel , true ) ;
2356
+ #endif
2357
+ AbsoluteLayout . SetLayoutBounds ( _errorLabel , _errorTextRect ) ;
2358
+ }
2359
+ else
2360
+ {
2361
+ _errorLabel . IsVisible = false ;
2362
+ #if ANDROID
2363
+ UpdateLabelAccessibilityImportance ( _errorLabel , false ) ;
2364
+ #endif
2365
+ }
2366
+ }
2367
+
2368
+ }
2369
+
2370
+ /// <summary>
2371
+ /// Applies the label style to a label control.
2372
+ /// </summary>
2373
+ void ApplyLabelStyle ( Label label , LabelStyle style )
2374
+ {
2375
+ if ( label == null || style == null )
2376
+ return ;
2377
+
2378
+ label . FontSize = style . FontSize ;
2379
+ label . FontFamily = style . FontFamily ;
2380
+ label . FontAttributes = style . FontAttributes ;
2381
+ label . TextColor = style . TextColor ;
2382
+ label . FontAutoScalingEnabled = style . FontAutoScalingEnabled ;
2383
+
2384
+ }
2385
+
2386
+ /// <summary>
2387
+ /// Disposes and removes the assistive labels (helper and error labels) from the control
2388
+ /// </summary>
2389
+ void DisposeAssistiveLabels ( )
2390
+ {
2391
+ if ( _helperLabel != null && Children . Contains ( _helperLabel ) )
2392
+ Children . Remove ( _helperLabel ) ;
2393
+ if ( _errorLabel != null && Children . Contains ( _errorLabel ) )
2394
+ Children . Remove ( _errorLabel ) ;
2395
+
2396
+ _helperLabel = null ;
2397
+ _errorLabel = null ;
2398
+ }
2399
+
2242
2400
/// <summary>
2243
2401
/// Returns the resource dictionary for the current theme of the parent element.
2244
2402
/// </summary>
0 commit comments