Xamarin.Forms: разделить градиент между двумя представлениями - PullRequest
0 голосов
/ 05 марта 2020

У меня есть пользовательский фрейм, созданный в Xamarin.Forms, который позволяет создавать градиентный фон. Я пытаюсь создать составную фигуру из двух разных фреймов, имеющих градиентный фон, но я хочу, чтобы градиент распределялся между ними. Я получил желаемый эффект с помощью Skia.Sharp.Forms, но я хотел бы знать, есть ли способ сделать это с помощью только Xamarin.Forms и пользовательских средств визуализации.

Пример того, что я ищу для:

enter image description here

Пример того, что я получаю при использовании двух пользовательских рамок: (не обращайте внимания на слегка отличающуюся форму)

enter image description here

РЕДАКТИРОВАТЬ

Моя идея заключается в том, что я хочу инкапсулировать два кадра (или любые элементы управления по этому вопросу) в Пользовательская сетка с заданными цветами градиента. Затем в пользовательском рендере Grid устанавливает фоны дочерних элементов управления на градиент. Таким образом, LinearGradient имеет начальную точку (0,0) родительской сетки и не создает новый градиент для каждого дочернего элемента. Вот некоторый код, чтобы объяснить, что я имею в виду, я просто еще не выяснил, в какой части я устанавливаю фоны для детей с градиентом, SetLayerPaint (метод, похоже, не работает ..)

        protected override void DispatchDraw(Canvas canvas)
    {
        _gradient = new Android.Graphics.LinearGradient(
            0, 0, Width, Height,
            new int[] { _startColor.ToAndroid(), _middleColor.ToAndroid(), _endColor.ToAndroid() },
            null,
            Android.Graphics.Shader.TileMode.Mirror);

        for(var i = 0; i < ChildCount; i++ )
        {
            var paint = new Android.Graphics.Paint()
            {
                Dither = true
            };
            paint.SetShader(_gradient);
            var child = GetChildAt(i);
            child.SetLayerPaint(paint);
        }
        base.DispatchDraw(canvas);
    }

Кто-нибудь знает, возможно ли это?

1 Ответ

0 голосов
/ 11 марта 2020

Вот мое решение: пользовательский рендер для Grid

public class GradientGridRenderer_Android : ViewRenderer
{
    private Xamarin.Forms.Color _startColor;
    private Xamarin.Forms.Color _middleColor;
    private Xamarin.Forms.Color _endColor;

    LinearGradient _gradient;

    public GradientGridRenderer_Android(Context context)
        : base(context) { }

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
    {
        base.OnElementChanged(e);
        if(e.NewElement != null && e.NewElement is GradientGrid grid)
        {
            _startColor = grid.StartColor;
            _middleColor = grid.MiddleColor;
            _endColor = grid.EndColor;
        }
    }

    protected override void DispatchDraw(Canvas canvas)
    {
        base.DispatchDraw(canvas);
        _gradient = new LinearGradient(
                0, 0, Width, Height,
                new int[]
                {
                    _startColor.ToAndroid(),
                    _middleColor.ToAndroid(),
                    _endColor.ToAndroid(),
                },
                null,
                Shader.TileMode.Mirror);
        for (var i = 0; i < ChildCount; i++)
        {
            var child = GetChildAt(i);
            if(child is FrameRenderer_Android gFrame)
            {
                gFrame.Gradient = _gradient;
                gFrame.Invalidate();
            }
        }
    }
}

Здесь пользовательский рендер для Child, при необходимости вы можете абстрагировать его и создать любое количество пользовательских рендереров, которые принимают градиент , но для моих целей мне просто нужен был фрейм.

public class FrameRenderer_Android : Xamarin.Forms.Platform.Android.AppCompat.FrameRenderer
    {
        public LinearGradient Gradient;

        public FrameRenderer_Android(Context context)
            : base(context) { }

        protected override void DispatchDraw(Canvas canvas)
        {
            if(Control != null && Gradient != null)
            {
                var paint = new Android.Graphics.Paint()
                {
                    Dither = true,
                };
                paint.SetShader(Gradient);
                canvas.DrawPaint(paint);
            }
            base.DispatchDraw(canvas);
        }
    }

А вот xaml

<ContentPage.Content>
        <cntrl:GradientGrid RowSpacing="0"
                      Margin="0,20,0,0"
                   StartColor="{StaticResource GracePink}"
                   MiddleColor="{StaticResource GracePurple}"
                   EndColor="{StaticResource GraceDarkPurple}"
                            IsClippedToBounds="True">
            <Grid.RowDefinitions>
                <RowDefinition Height="10*"/>
                <RowDefinition Height="90*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <cntrl:CustomFrame Grid.Column="2"
                               Grid.Row="0"
                               IsClippedToBounds="True"
                               CornerRadius="20,20,0,0">

            </cntrl:CustomFrame>
            <cntrl:CustomFrame Grid.ColumnSpan="4"
                               Grid.Row="1"
                               IsClippedToBounds="True"
                               CornerRadius="40,40,0,0">

            </cntrl:CustomFrame>
        </cntrl:GradientGrid>
    </ContentPage.Content>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...