首页 > 解决方案 > 可绑定属性未更新 iOS 上的视图

问题描述

我正在 xamarin.forms 上创建一个跨平台应用程序。我需要一个具有渐变背景的自定义渲染器,并且我已经创建了它,它在 android 和 ios 上都运行良好。但是,当我想更改渐变背景的颜色时,它在 iOS 上不起作用。

测试.xaml.cs

namespace KiaiDay
{
    public class TesteViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private Color _startColor = Color.Green;
        public Color SStartColor
        {
            get => _startColor;
            set { _startColor = value; OnPropertyChanged(nameof(SStartColor)); }
        }

        private Color _endColor = Color.Blue;
        public Color EEndColor
        {
            get => _endColor;
            set { _endColor = value; OnPropertyChanged(nameof(EEndColor)); }
        }

        public ICommand Select
        {
            get => new Command(() =>
            {
                SStartColor = Color.Red;
                EEndColor = Color.Brown;
            });
        }

        #region INotifyPropertyChanged Implementation
        void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged == null)
                return;

            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class teste : ContentPage
    {
        public teste()
        {
            BindingContext = new TesteViewModel();
            InitializeComponent();
        }

    }
}

测试.xaml

    <ContentPage.Content>
        <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
            <local:ShadowFrame StartColor="{Binding SStartColor}" EndColor="{Binding EEndColor}" HorizontalOptions="Center" VerticalOptions="Center">
                <Label Text="Teste"/>
                <local:ShadowFrame.GestureRecognizers>
                    <TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Select}"/>
                </local:ShadowFrame.GestureRecognizers>
            </local:ShadowFrame>
        </StackLayout>
    </ContentPage.Content>

PCL 中的自定义渲染器

public class ShadowFrame : Frame
    {
        public static BindableProperty ElevationProperty = BindableProperty.Create(nameof(Elevation), typeof(float), typeof(ShadowFrame), default(float));
        public static readonly BindableProperty StartColorProperty = BindableProperty.Create(nameof(StartColor), typeof(Color), typeof(ShadowFrame), default(Color));
        public static readonly BindableProperty EndColorProperty = BindableProperty.Create(nameof(EndColor), typeof(Color), typeof(ShadowFrame), default(Color));

        public float Elevation
        {
            get { return (float)GetValue(ElevationProperty); }
            set { SetValue(ElevationProperty, value); }
        }

        public Color StartColor
        {
            get { return (Color)GetValue(StartColorProperty); }
            set { SetValue(StartColorProperty, value); }
        }

        public Color EndColor
        {
            get { return (Color)GetValue(EndColorProperty); }
            set { SetValue(EndColorProperty, value); }
        }
    }

iOS Renderer(我认为问题出在这里)

[assembly: ExportRenderer(typeof(ShadowFrame), typeof(ShadowFrameRenderer))]
namespace KiaiDay.iOS.Renderers
{
    public class ShadowFrameRenderer : FrameRenderer
    {
        CAGradientLayer gradientLayer;
        private Color StartColor { get; set; }
        private Color EndColor { get; set; }
        CGRect rect;

        public static void Initialize()
        {

            // empty, but used for beating the linker
        }

        public ShadowFrameRenderer() => gradientLayer = new CAGradientLayer();

        public override void Draw(CGRect rect)
        {
            this.rect = rect;
            var stack = (ShadowFrame)this.Element;
            StartColor = stack.StartColor;
            EndColor = stack.EndColor;
            CGColor startColor = this.StartColor.ToCGColor();
            CGColor endColor = this.EndColor.ToCGColor();
            #region for Vertical Gradient  
            //var gradientLayer = new CAGradientLayer();     
            #endregion
            #region for Horizontal Gradient  
            //var gradientLayer = new CAGradientLayer()
            //{
            //    StartPoint = new CGPoint(0, 0.5),
            //    EndPoint = new CGPoint(1, 0.5)
            //};
            #endregion
            gradientLayer.Frame = rect;
            gradientLayer.Colors = new CGColor[] {
                startColor,
                endColor
            };

            NativeView.Layer.InsertSublayer(gradientLayer, 0);
            base.Draw(rect);
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
        {
            base.OnElementChanged(e);
            var stack = (ShadowFrame)e.NewElement;

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

            try
            {
                this.StartColor = stack.StartColor;
                this.EndColor = stack.EndColor;
                UpdateShadow();
                Draw(rect);
            }

            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("ERROR:", ex.Message);
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            var stack = (ShadowFrame) sender;

            if (e.PropertyName == ShadowFrame.ElevationProperty.PropertyName)
            {
                UpdateShadow();
            }
            if (e.PropertyName == ShadowFrame.StartColorProperty.PropertyName)
            {
                this.StartColor = stack.StartColor;
            }
            if (e.PropertyName == ShadowFrame.EndColorProperty.PropertyName)
            {
                this.EndColor = stack.EndColor;
            }
        }


        private void UpdateShadow()
        {

            var shadowFrame = (ShadowFrame)Element;

            // Update shadow to match better material design standards of elevation
            Layer.ShadowRadius = shadowFrame.Elevation;
            Layer.ShadowColor = UIColor.Gray.CGColor;
            Layer.ShadowOffset = new CGSize(2, 2);
            Layer.ShadowOpacity = 0.80f;
            Layer.ShadowPath = UIBezierPath.FromRect(Layer.Bounds).CGPath;
            Layer.MasksToBounds = false;
        }
    }
}

通过命令更改颜色后,我想立即更新 iOS 视图。

标签: iosxamarin.formscustom-renderer

解决方案


如果您更改属性并且视图未更新,则问题必须在OnElementPropertyChanged.

您需要调用UpdateShadow()Draw()


推荐阅读