@@ -234,10 +234,10 @@ static void ApplyCancelButtonOverlay(UISearchBar uiSearchBar, UIButton cancelBut
234234 }
235235
236236 // Remove any overlay from a previous call (e.g. color change or re-focus)
237- parentView . ViewWithTag ( CancelButtonColorOverlayTag ) ? . RemoveFromSuperview ( ) ;
237+ uiSearchBar . ViewWithTag ( CancelButtonColorOverlayTag ) ? . RemoveFromSuperview ( ) ;
238238
239239 // Find the UIImageView that UIButton uses to render the X icon.
240- // We need its frame in the parent view's coordinate space to position the overlay .
240+ // We need its frame to determine the rendered image size .
241241 var iv = cancelButton . FindDescendantView < UIImageView > ( ) ;
242242 if ( iv == null )
243243 return ;
@@ -279,33 +279,34 @@ static void ApplyCancelButtonOverlay(UISearchBar uiSearchBar, UIButton cancelBut
279279 }
280280 } ) . ImageWithRenderingMode ( UIImageRenderingMode . AlwaysOriginal ) ;
281281
282- // Add the overlay as the last (topmost) sibling of the cancel button so it
283- // renders on top of UIButton's layer-drawn X icon.
284- var overlay = new UIImageView ( iconFrameInParent )
282+ // Add the overlay as the last (topmost) sibling of the cancel button.
283+ // Use Auto Layout constraints so the overlay stays centered over the X icon
284+ // on rotation, multitasking split view, or dynamic type changes.
285+ var overlay = new UIImageView
285286 {
286287 Image = coloredImage ,
287288 ContentMode = UIViewContentMode . ScaleAspectFit ,
288289 Tag = CancelButtonColorOverlayTag ,
289290 UserInteractionEnabled = false ,
291+ TranslatesAutoresizingMaskIntoConstraints = false ,
290292 } ;
291293
292294 parentView . AddSubview ( overlay ) ;
295+
296+ NSLayoutConstraint . ActivateConstraints ( new NSLayoutConstraint [ ]
297+ {
298+ overlay . CenterXAnchor . ConstraintEqualTo ( cancelButton . CenterXAnchor ) ,
299+ overlay . CenterYAnchor . ConstraintEqualTo ( cancelButton . CenterYAnchor ) ,
300+ overlay . WidthAnchor . ConstraintEqualTo ( imageSize . Width ) ,
301+ overlay . HeightAnchor . ConstraintEqualTo ( imageSize . Height ) ,
302+ } ) ;
293303 }
294304
295305 static void RemoveCancelButtonOverlay ( UISearchBar uiSearchBar )
296306 {
297- // The overlay is added as a direct sibling of the cancel button (child of cancel button's parent).
298- // Find the cancel button's parent view and remove the overlay from it by tag.
299- var cancelButtonParent = uiSearchBar . FindDescendantView < UIButton > (
300- btn => btn . FindParent ( v => v is UITextField ) == null ) ? . Superview ;
301- cancelButtonParent ? . ViewWithTag ( CancelButtonColorOverlayTag ) ? . RemoveFromSuperview ( ) ;
302-
303- // Also check one level deeper in the hierarchy in case the search bar layout changes
304- foreach ( var subview in uiSearchBar . Subviews )
305- {
306- foreach ( var child in subview . Subviews )
307- child . ViewWithTag ( CancelButtonColorOverlayTag ) ? . RemoveFromSuperview ( ) ;
308- }
307+ // UIView.ViewWithTag searches the entire subtree recursively, so it finds the overlay
308+ // regardless of where it was placed in the search bar's view hierarchy.
309+ uiSearchBar . ViewWithTag ( CancelButtonColorOverlayTag ) ? . RemoveFromSuperview ( ) ;
309310 }
310311
311312 internal static void UpdateSearchIcon ( this UISearchBar uiSearchBar , ISearchBar searchBar )
0 commit comments