【问题标题】:Custom ViewRenderer<> displays Forms element behind the native control自定义 ViewRenderer<> 在原生控件后面显示 Forms 元素
【发布时间】:2020-05-31 03:51:38
【问题描述】:

在我的 Xamarin Forms 应用程序中,我有一个派生自 ContentView 的自定义视图。在 iOS 和 macOS 上,我想用本机控件 ([UI|NS]SegmentedControl) 替换此视图。所以我创建了一个从 ViewRenderer 派生的渲染器并实现了它。

它工作正常,但有一个缺陷。原始的 Forms 控件(在渲染器中称为 Element)显示在 UISegmentedControl 后面。我的期望是使用 ViewRenderer 时只会呈现原生控件。

对 Forms 元素的外观所做的任何更改都会反映在本机控件上,因此简单地隐藏它或使其透明是行不通的。

这是我的 iOS 渲染器。

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 是简单地从ContentView 派生的,以BoxView 作为内容。这是它在 iOS 上的样子:

我对渲染器的理解是自定义渲染器完全覆盖表单元素。我在这里错过了什么大事吗?可以使用 ViewRenderer 将 Xamarin ContentView 完全替换为原生控件吗?

编辑:在上面的示例中,我使用 BoxView 作为用于 UWP 的实际跨平台选择器的占位符。真正的控件是包含切换按钮的 StackLayout。这是 macOS 上显示问题的屏幕截图。

最后,设置 Element.Content.IsVisible = false 起作用了。

【问题讨论】:

    标签: xamarin.forms


    【解决方案1】:

    是的,您可以完全替换 ContentView 的原生控件。而你已经这样做了。

    您所看到的是 ContentView 的(本机控件)子视图(您已作为 BoxView 提供)显示。

    如果您不想要任何额外的子内容,请不要添加 Content 和/或子类化与 ContentView 不同的类。可能的修复:

    • 只需删除Content = new BoxView ... 行。我相信这将导致“没有孩子可以展示”。如果我错了,那么谷歌如何“没有内容”。
    • 您也许可以直接继承View。如果没有,那么您可以将通常在没有 Content 的情况下使用的简单事物子类化 - 也许是 BoxView。
    • 后备解决方案:不要BoxView 上设置BackgroundColor。结果是一个看不见的盒子。 (我意识到这并不是您真正想要的:您希望避免不必要地创建视图。)[不可见的框有时可用作在布局中添加不可见空间的一种有用的方法-一种边距的替代方法。]

    根据您的评论,听起来您想在一个平台上“抑制”给定的Content,因为它的角色被自定义控件所包含。为此,请在子级上设置IsVisible 属性,并在该平台上将其设置为false。这将禁止为子级及其后代生成平台控件。

    注意:不要尝试从自定义渲染器中操作Element 属性(例如IsVisible)。这是在布局/绘制序列中的错误时刻执行的。相反,从视图的代码后面或通过绑定执行。在代码中测试平台的一种方法是 Xamarin.Essentials.DeviceInfo.Platform。

    【讨论】:

    • 我的示例使用橙色 BoxView 作为 SO 的简单占位符。实际上,它是一个跨平台的 ContentView,包含执行与分段控件相同的功能的切换按钮。因此,整个控件都绘制在本机表示之后。我希望它只呈现本机控件。我将更新 OP 以使其更清晰。
    • @JimMarquardt。它是什么并不重要。关键是它是ContentView的子视图。该子项独立于 ContentView 的控件本身。如果您不希望子视图覆盖在 ConventView 的控件上,则不要在此处添加子视图。您定义的是嵌套控件。 XAML 中的视图层次结构变成了本机平台上的控制层次结构。证据表明,“替换元素的控件”并不会消除其中子元素的层次结构。它所做的只是替换作为“容器”的控件。
    • @JimMarquardt - 我认为您将 ContentView 的 Content 与“ContentView”对象本身混淆了。您认为 Content 是平台渲染器渲染的内容,因此将被您提供的自定义 Control 替换。不,ContentView 的Control 是一些容器控件,您已成功替换。 Content 不是由 ContentView 渲染器 rendered (尽管在 Xamarin 视图类中测量/定位了它的 children,而不是渲染器) -它由处理您作为内容提供的视图的任何渲染器渲染。
    • 我已经添加到帖子末尾,提到在平台上隐藏内容。
    • 我在 OnElementChanged() 中添加了 Element.Content.IsVisible = false,这很有效。感谢您的澄清。我确信我之前尝试过。
    【解决方案2】:

    根据 Xamarin 自定义渲染器的文档,只需覆盖 Xamarin.Forms 外观和行为。 在这里,您将自定义内容视图背景设置为橙色,然后在您的自定义渲染器中您没有覆盖它,并且我知道 iOS 中的默认背景是透明的,因此仍为橙色是有意义的。 希望对你有用?

    【讨论】:

    • 我更改了 Element 的背景以匹配页面背景,并且旧控件现在很好地隐藏在本机控件后面。这很好用。我只是不确定默认渲染器是如何处理这个的(特别是因为它需要对背景颜色的引用,并且如果背景发生变化也不会更新它)。但它适用于我的场景。
    • OnElementProppertyChanged 将为您提供后台属性更改,您可以覆盖
    猜你喜欢
    • 2021-06-18
    • 2013-02-23
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 2020-03-29
    相关资源
    最近更新 更多