未调用Xamarin IOS自定义渲染器重写的Draw方法

问题描述 投票:0回答:1

我正在尝试在列表视图中加载自定义的滑块控件(具有Accordeon行为)。当View加载时,所有listview元素都被折叠,因此滑块控件的可见性为false。我观察到在控件不可见时未调用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;然后我得到了自定义控件。

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

任何人都有一个想法,当控件不可见时如何正确加载自定义渲染器?

谢谢!

xamarin xamarin.forms xamarin.ios custom-renderer
1个回答
1
投票

假设渲染器覆盖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. ...
    }
    ...
}
© www.soinside.com 2019 - 2024. All rights reserved.