Xamarin IOS Custom Renderer переопределяет метод Draw, не вызываемый - PullRequest
0 голосов
/ 24 сентября 2019

Я пытаюсь загрузить настроенный элемент управления ползунка в виде списка (с поведением accordeon).Когда представление загружается, все элементы списка свернуты, поэтому видимость элемента управления ползунка ложна.Я заметил, что переопределенный метод Draw в рендере ios не вызывается, пока элемент управления не виден, поэтому я в конечном итоге имею собственный элемент управления в своем просмотре списка.

Я воспроизвел проблему в отдельном проекте:

У меня есть пользовательское средство визуализации 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, когда элемент управления невидим.

У кого-нибудь есть идеи, как правильно загрузить пользовательский рендерер, когда элемент управления не отображается?

Спасибо!

1 Ответ

0 голосов
/ 24 сентября 2019

Предполагается, что средство визуализации переопределяет 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. ...
    }
    ...
}
...