Xamarin IOS 自定义渲染器覆盖未调用绘制方法

Xamarin IOS Custom Renderer overriden Draw method not called

我正在尝试在列表视图中加载自定义滑块控件(具有手风琴行为)。当视图加载时,所有列表视图元素都折叠起来,因此滑块控件的可见性为假。我观察到 ios 渲染器中覆盖的 Draw 方法在控件不可见时未被调用,因此我最终在我的列表视图中拥有本机控件。

我已经在一个单独的项目中重现了这个问题:

我有 IOS 自定义渲染器:

public class CustomGradientSliderRenderer : SliderRenderer
{
    public CGColor StartColor { get; set; }
    public CGColor CenterColor { get; set; }
    public CGColor EndColor { get; set; }
    protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
    {

        if (Control == null)
        {
            var customSlider = e.NewElement as CustomGradientSlider;
            StartColor = customSlider.StartColor.ToCGColor();
            CenterColor = customSlider.CenterColor.ToCGColor();
            EndColor = customSlider.EndColor.ToCGColor();

            var slider = new SlideriOS
            {
                Continuous = true,

                Height = (nfloat)customSlider.HeightRequest
            };

            SetNativeControl(slider);
        }

        base.OnElementChanged(e);
    }

    public override void Draw(CGRect rect)
    {
        base.Draw(rect);

        if (Control != null)
        {
            Control.SetMinTrackImage(CreateGradientImage(rect.Size), UIControlState.Normal);
        }
    }

    void OnControlValueChanged(object sender, EventArgs eventArgs)
    {
        ((IElementController)Element).SetValueFromRenderer(Slider.ValueProperty, Control.Value);
    }

    public UIImage CreateGradientImage(CGSize rect)
    {
        var gradientLayer = new CAGradientLayer()
        {
            StartPoint = new CGPoint(0, 0.5),
            EndPoint = new CGPoint(1, 0.5),
            Colors = new CGColor[] { StartColor, CenterColor, EndColor },
            Frame = new CGRect(0, 0, rect.Width, rect.Height),
            CornerRadius = 5.0f
        };

        UIGraphics.BeginImageContext(gradientLayer.Frame.Size);
        gradientLayer.RenderInContext(UIGraphics.GetCurrentContext());
        var image = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();

        return image.CreateResizableImage(UIEdgeInsets.Zero);
    }
}

public class SlideriOS : UISlider
{
    public nfloat Height { get; set; }

    public override CGRect TrackRectForBounds(CGRect forBounds)
    {
        var rect = base.TrackRectForBounds(forBounds);
        return new CGRect(rect.X, rect.Y, rect.Width, Height);
    }
}

带有代码隐藏的视图:

Main.xaml:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage
    x:Class="GradientSlider.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:GradientSlider">
    <ContentPage.Content>

    <Grid>
    <StackLayout  x:Name="SliderContainer">

        <local:CustomGradientSlider
            x:Name="mySlider"
            CenterColor="#feeb2f"
            CornerRadius="16"
            EndColor="#ba0f00"
            HeightRequest="20"
            HorizontalOptions="FillAndExpand"
            Maximum="10"

            Minimum="0"
            StartColor="#6bab29"
            VerticalOptions="CenterAndExpand"
            MaximumTrackColor="Transparent"

            ThumbColor="green"
            />
        <Label x:Name="lblText" Text="txt"
               VerticalOptions="Center" HorizontalOptions="Center"/>
    </StackLayout>

    <Button Text="Magic" Clicked="Button_Tapped" WidthRequest="100" HeightRequest="50" VerticalOptions="Center" HorizontalOptions="Center"/>

         </Grid>
        </ContentPage.Content>

</ContentPage>

Main.xaml.cs:

    using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace GradientSlider
{
    public partial class MainPage : ContentPage, INotifyPropertyChanged

    {

        public MainPage()
        {
            InitializeComponent();
            SliderContainer.IsVisible = false;
        }


        void Button_Tapped(object sender,ClickedEventArgs a)
        {
            SliderContainer.IsVisible = !SliderContainer.IsVisible;

        }


    }
}

所以在上面的场景中你可以看到当我加载 main.xaml 时控件是不可见的 (SliderContainer.IsVisible = false;) 在这种情况下我得到一个本地滑块控件而不是我的自定义一。如果我在构造函数中更改 SliderContainer.IsVisible = true;然后我得到我的自定义控件。

经过调查,我意识到如果控件在视图加载时不可见,public override void Draw(CGRect rect) 不会被调用。我找不到在控件不可见时触发 Draw 方法的任何解决方案。

有人知道如何在控件不可见时正确加载自定义渲染器吗?

谢谢!

假设渲染器覆盖 OnElementPropertyChanged:

protected override void OnElementChanged(ElementChangedEventArgs<MyFormsSlider> e)
{
    if (e.NewElement != null)
    {
        if (Control == null)
        {
            // Instantiate the native control and assign it to the Control property with
            // the SetNativeControl method
            SetNativeControl(new MyNativeControl(...
    ...
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    base.OnElementPropertyChanged(sender, e);

    //assuming MyFormsSlider derives from View / VisualElement; the latter has IsVisibleProperty
    if (e.PropertyName == MyFormsSlider.IsVisibleProperty.PropertyName)
    {
        //Control is the control set with SetNativeControl
        Control. ...
    }
    ...
}