0
votes

In my Xamarin Forms app, I have a custom view that derives from ContentView. On iOS and macOS, I would like to replace this view with a native control ([UI|NS]SegmentedControl). So I created a renderer that derives from ViewRenderer and implemented it.

It's working, but there is a flaw. The original Forms control (known as Element within the renderer) is displaying behind the UISegmentedControl. My expectation is that only the native control would be rendered when using ViewRenderer.

Any changes made to the appearance of the Forms element are reflected on the native control, so simply hiding it or making it transparent won't work.

Here's my iOS renderer.

public class CustomContentViewRenderer : ViewRenderer<CustomContentView, UISegmentedControl>
{
    protected override void OnElementChanged(ElementChangedEventArgs<CustomContentView> e) {
        base.OnElementChanged(e);

        if (e.NewElement != null ) {
            if ( Control == null )
                SetNativeControl(new UISegmentedControl(new string[] { "One", "Two", "Three" }));
        }
    }
}

CustomContentView here is simply derived from ContentView with a BoxView as content. Here's what it looks like on iOS: Overlapping controls

My understanding of renderers is that a custom renderer completely overrides the forms element. Am I missing something big here? Can ViewRenderer<> be used to completely replace a Xamarin ContentView with a native control?

EDIT: In the sample above I'm using a BoxView as a placeholder for the actual cross platform picker I use for UWP. The real control is a StackLayout containing toggle buttons. Here's a screen grab on macOS showing the issue.

macOS version of actual implementation

In the end, setting Element.Content.IsVisible = false worked.

2

2 Answers

0
votes

Yes, you can completely replace the ContentView's native control. And you have done so.

What you are seeing is that the (native control for the) child view (which you've provided as a BoxView) of the ContentView is also displaying.

If you don't want any additional child content, then don't add Content and/or subclass some different class than ContentView. Possible fixes:

  • Simply remove the Content = new BoxView ... line. I believe that will result in "no child to display". If I'm wrong, then google how to have "no Content".
  • You might be able to subclass View directly. If not, then you could subclass something simple that usually is used without Content - maybe a BoxView.
  • Fallback solution: don't set BackgroundColor on the BoxView. Result is an invisible box. (I realize that isn't really what you want: you want to avoid unnecessary creation of views.) [Invisible boxes are occasionally useful as a way to add invisible space in a layout - an alternative to margins.]

From your comment, it sounds like you want to "suppress" the given Content on one platform, as its role is subsumed by the custom control. To do this, have IsVisible property on the child, and set it to false on that platform. This will suppress generation of platform controls for the child and its descendents.

CAUTION: Don't try manipulating Element properties (such as IsVisible) from the custom renderer. This is executing at the wrong moment in the layout/draw sequence. Instead, do from view's code behind or via a Binding. One way to test platform in code is Xamarin.Essentials.DeviceInfo.Platform.

0
votes

as per as documentation of Xamarin custom renderers just override Xamarin.Forms appearance and behvoir. Here you gave custom content view background orange then in your custom renderer you didn't override it and as I know default background in iOS is transparent so make sense to still in orange color. Hope to be useful 😉