【问题标题】:Xamarin Forms iOS CustomRenderer not repaintingXamarin Forms iOS CustomRenderer不重绘
【发布时间】:2017-10-07 17:01:15
【问题描述】:

我有一个自定义渲染器来在 UITextView 中显示 HTML 格式的文本。如果我将文本硬编码到包含控件的页面的构造函数中(因此它被设置在自定义控件的 OnElementChanged 事件中),它显示得很好。如果我等待 api 调用以获取文本然后设置它(因此它在自定义控件的 OnElementPropertyChanged 事件中设置)它不会重新绘制。如果我更改设备的方向,则会出现文本。我需要添加什么才能让它在设置时显示文本?

[assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
namespace MyApp.iOS.Renderers
{
    class HtmlLabelRenderer : ViewRenderer<HtmlLabel, UITextView>
    {
        private UITextView _htmlTextView = new UITextView();
        protected override void OnElementChanged(ElementChangedEventArgs<HtmlLabel> e)
        {
            base.OnElementChanged(e);

            if (Element?.Text == null) return;

            SetHtmlText(Element.Text);
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (string.Equals(e.PropertyName, "Text", StringComparison.CurrentCultureIgnoreCase))
            {
                SetHtmlText(((HtmlLabel)sender).Text);
                _htmlTextView.SetNeedsDisplay();
            }
            base.OnElementPropertyChanged(sender, e);
        }

        private void SetHtmlText(string text)
        {
            var attr = new NSAttributedStringDocumentAttributes {DocumentType = NSDocumentType.HTML};
            var nsError = new NSError();

            _htmlTextView.Editable = false;
            _htmlTextView.AttributedText = new NSAttributedString(text, attr, ref nsError);
            _htmlTextView.DataDetectorTypes = UIDataDetectorType.All;
            SetNativeControl(_htmlTextView);
        }
    }
}

更新:我通过将 OnElementChanged 更改为:

    protected override void OnElementChanged(ElementChangedEventArgs<HtmlLabel> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null || Element == null) return;

        SetHtmlText(e.NewElement.Text ?? string.Empty);
        SetNativeControl(_htmlTextView);
    }

现在,如果我在页面上有多个 HtmlLabel,除了第一个显示。

【问题讨论】:

    标签: ios xamarin.forms custom-renderer


    【解决方案1】:

    尝试更改:

    _htmlTextView.SetNeedsDisplay();
    

    SetNeedsDisplay();
    

    或者,

    (Control ?? NativeView).SetNeedsDisplay();
    

    【讨论】:

    • 好的 - 只是为了确认一下,HtmlLabel 上的 Text 属性是可绑定属性吗?如果可以的话,你能把HtmlLabel的代码贴出来吗?
    • 不,没有 HtmlLabel 的代码 - public class HtmlLabel : Label { } 我将它添加到页面 然后在后面的代码中设置文本检索后 HtmlDescription.Text = notice.Details;
    • 啊!这可能是这里的脱节。当我从现有的表单控件派生时 - 我尝试从官方表单渲染器派生或至少确保本机控件的类型参数与表单使用的相同。我认为在这种情况下,您应该从Editor 而不是Label 派生。 Ref for more details
    • 在 android 端,我确实使用了一个标签 - 公共类 HtmlLabelRenderer:LabelRenderer - 将其更改为编辑器会如何影响它?我真的更愿意在 iOS 中使用 Label,但是虽然 格式很好地点击它们并没有做任何事情......
    • 如果您更改为Editor,您将在Android 中更改为EditText,如[链接] (developer.xamarin.com/guides/xamarin-forms/…) 中所述。请注意 - 它只是推测这可能是这个特定问题的根本原因。
    【解决方案2】:

    Sharada Gururaj 是对的,改为从适用于 iOS 的编辑器派生 .. 但破坏了 Android。虽然这看起来很暴力,但我使用条件编译来让它工作......

    namespace MyApp.Renderers
    {
    #if __IOS__
        public class HtmlLabel : Editor
        {
        }
    #else
        public class HtmlLabel : Label
        {
        }
    #endif
    }
    

    这里是安卓

    [assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
    
    namespace MyApp.Droid.Renderers
    {
        public class HtmlLabelRenderer : LabelRenderer
        {
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
            {
                base.OnElementChanged(e);
    
                var view = (HtmlLabel)Element;
                if (view?.Text == null) return;
    
                SetHtmlText(view.Text);
            }
    
            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
                if (e.PropertyName == Label.TextProperty.PropertyName)
                {
                    SetHtmlText(((HtmlLabel) sender).Text);
                }
            }
    
            private void SetHtmlText(string text)
            {
                var encodedText = (((int)Build.VERSION.SdkInt) >= 24) ? Html.FromHtml(text, FromHtmlOptions.ModeLegacy) :
    #pragma warning disable 618
       // need this for backward compatability
       Html.FromHtml(text);
    #pragma warning restore 618
                Control.MovementMethod = LinkMovementMethod.Instance;
                Control.SetText(encodedText, TextView.BufferType.Spannable);
            }
        }
    }
    

    【讨论】:

    • 我更新了我的答案,您应该能够在两个平台上从相同的东西中派生出来,只需使用ViewRenderer&lt;Label, NativeType&gt;
    【解决方案3】:

    您的自定义 HtmlLabel 类应该能够从 Android 和 iOS 上的相同事物派生

    namespace YourNameSpace
    {
        public class HtmlLabel : Label
        {
        }
    }
    

    Android 的渲染器应该是这样的

    [assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
    namespace YourNameSpace.Droid
    {
        public class HtmlLabelRenderer : ViewRenderer<Label, TextView>
        {
            TextView _textView;
    
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
            {
                base.OnElementChanged(e);
    
                if (Element == null)
                    return;
    
                if(Control == null)
                {
                    _textView = new TextView(Context);
                    SetHtmlText(Element.Text);
                    SetNativeControl(_textView);
                }
            }
    
            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
    
                if (Element == null || Control == null)
                    return;
    
                if (e.PropertyName == HtmlLabel.TextProperty.PropertyName)
                {
                    SetHtmlText(Element.Text);
                }
            }
    
            private void SetHtmlText(string text)
            {
    
                if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.N)
                {
                    _textView.TextFormatted = Html.FromHtml(text, Android.Text.FromHtmlOptions.ModeCompact);
                }
                else
                {
                    _textView.TextFormatted = Html.FromHtml(text);
                }
            }
        }
    }
    

    在 iOS 上看起来应该非常相似

    [assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
    namespace YourNameSpace.iOS
    {
        public class HtmlLabelRenderer : ViewRenderer<Label, UITextView>
        {
            UITextView _textView;
    
            protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
            {
                base.OnElementChanged(e);
    
                if (Element == null)
                    return;
    
                if(Control == null)
                {
                    _textView = new UITextView();
                    SetHtmlText(Element.Text);
                    SetNativeControl(_textView);
                }
            }
    
            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
    
                if (Element == null || Control == null)
                    return;
    
                if (e.PropertyName == HtmlLabel.TextProperty.PropertyName)
                {
                    SetHtmlText(Element.Text);
                }
            }
    
            private void SetHtmlText(string text)
            {
                var attr = new NSAttributedStringDocumentAttributes { DocumentType = NSDocumentType.HTML };
                var nsError = new NSError();
    
                _textView.Editable = false;
                _textView.AttributedText = new NSAttributedString(text, attr, ref nsError);
                _textView.DataDetectorTypes = UIDataDetectorType.All;
            }
        }
    }
    

    我在 Android 上对其进行了测试,它工作正常,当文本发生变化时调用 OnElementPropertyChanged 和一切。但是,我家里没有 Mac 来试用 iOS Renderer,所以我只是假设它的功能几乎相同。

    【讨论】:

      猜你喜欢
      • 2020-04-22
      • 1970-01-01
      • 2017-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2018-08-06
      • 1970-01-01
      相关资源
      最近更新 更多