xamarin格式的渐变stacklayout

时间:2017-07-04 08:05:19

标签: c# xaml xamarin.forms

我正在研究Xamarin表格。我需要一个渐变stacklayout视图,其宽度设置为堆栈布局,大于设备的纵向宽度。设置此宽度将确保stacklayout适合纵向视图,并且在横向中可以看到具有宽度的stacklayout。在这里,我需要一个从上到下的渐变stacklayout。我已经看到一些带有自定义渲染器的帖子,用于stacklayout,效果很好。

但是当我使用这些渲染器时,我可以看到在实时场景中将方向从纵向更改为横向时,绘制的渐变布局宽度被视为纵向宽度,其余区域为空。参见附件中的图片

肖像

[![肖像] [1] [1]

和风景

landscape

以下是XAML代码图像enter image description here

<AbsoluteLayout>
<Image Source="img_bg.png" Aspect="AspectFill" VerticalOptions="FillAndExpand" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"/>
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All" Spacing="0" Padding="0,20,0,0">
  <Image Source="img_logo.png" HorizontalOptions="Center" WidthRequest="200" HeightRequest="80"/>
  <ScrollView>
          <local:GradientStack StartColor="#99ddde" EndColor="#2896b1" HeightRequest="375" WidthRequest="300" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Padding="25,5,25,0" Margin="20,25,20,0" Spacing="0">
      <Label Text="Log in" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="34"/>
      <Label Text="Username" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="20" Margin="0,10,0,0"/>
      <local:CustomBorderEntry x:Name="txtUserName" HorizontalOptions="FillAndExpand"
                               HeightRequest="38" Margin="0,5,0,0"
                               BackgroundColor="#e5f8fc" FontSize="16"
                               TextColor ="#201f1f"
                               HorizontalTextAlignment="Start" />
      <Label Text="Password" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="20" Margin="0,10,0,0"/>
      <local:CustomBorderEntry x:Name="txtPassword" HorizontalOptions="FillAndExpand"
                               HeightRequest="38" Margin="0,5,0,0"
                               BackgroundColor="#e5f8fc" FontSize="16"
                               TextColor ="#201f1f"
                               HorizontalTextAlignment="Start" IsPassword="true"/>
      <Label Text="Event Code" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="20" Margin="0,10,0,0"/>
      <local:CustomBorderEntry x:Name="txtEventCode" HorizontalOptions="FillAndExpand"
                               HeightRequest="36" Margin="0,5,0,0"
                               BackgroundColor="#e5f8fc" FontSize="16"
                               TextColor ="#201f1f"
                               HorizontalTextAlignment="Start"/>
      <StackLayout Margin="0,20,0,0" Padding="0,1,0,0" BackgroundColor="#e5f8fc" HorizontalOptions="FillAndExpand" HeightRequest="45">
        <local:GradientStack StartColor="#2c7f9d" EndColor="#0e5a8c" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" x:Name="slLogin">
          <Label Text="Log in" FontSize="20" TextColor="#e5f8fc" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
        </local:GradientStack>            
      </StackLayout>
    </local:GradientStack>
  </ScrollView>
</StackLayout>

自定义控件:

public class GradientStack : StackLayout
{
    public Color StartColor { get; set; }
    public Color EndColor { get; set; }
}

自定义渲染器:

public class GradientStackRenderer : VisualElementRenderer<GradientStack>
{
    public override void Draw(CGRect rect)
    {
        base.Draw(rect);
        CAGradientLayer layer = new CAGradientLayer();
        layer.Frame = rect;
        layer.Colors = new CGColor[] {
            Element.StartColor.ToCGColor(),
            Element.EndColor.ToCGColor()
        };
        Layer.InsertSublayer(layer, 0);
    }
}

2 个答案:

答案 0 :(得分:2)

这是解决方案。当堆栈布局的大小发生变化时,我们需要强制重绘。

[assembly: ExportRenderer(typeof(GradientStack), typeof(GradientStackRenderer))]

namespace yournamespace.iOS
{
    class GradientStackRenderer : ViewRenderer<StackLayout, UIView>
    {

        public override void Draw(CGRect rect)
        {
            base.Draw(rect);
            CAGradientLayer layer = new CAGradientLayer();
            layer.Frame = rect;
            layer.Colors = new CGColor[]
            {
                ((GradientStack)Element).StartColor.ToCGColor(),
                ((GradientStack)Element).EndColor.ToCGColor()
            };

            if(Layer.Sublayers[0] is CAGradientLayer)
                Layer.ReplaceSublayer(Layer.Sublayers[0], layer);
            else
                Layer.InsertSublayer(layer, 0);

        }

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

            if(e.PropertyName=="Width")
                SetNeedsDisplay();
        }


    }
}

我们也不想在每次绘制时添加图层,因此如果已经在子图层中,我们会检查并替换我们的图层。

我也会删除不必要的尺寸请求

    <AbsoluteLayout>
        <Image Source="img_bg.png" Aspect="AspectFill" VerticalOptions="FillAndExpand" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"/>
        <StackLayout  AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All" Spacing="0" Padding="0,20,0,0">
            <Image Source="img_bg.png" HorizontalOptions="Center" WidthRequest="200" HeightRequest="80"/>
            <ScrollView>
                <local:GradientStack StartColor="#99ddde" EndColor="#2896b1" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Padding="25,5,25,20" Margin="20,25,20,0" Spacing="0">
                    <Label Text="Log in" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="34"/>
                    <Label Text="Username" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="20" Margin="0,10,0,0"/>
                    <local:CustomBorderEntry x:Name="txtUserName" HorizontalOptions="FillAndExpand"
                           HeightRequest="38" Margin="0,5,0,0"
                           BackgroundColor="#e5f8fc" FontSize="16"
                           TextColor ="#201f1f"
                           HorizontalTextAlignment="Start" />
                    <Label Text="Password" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="20" Margin="0,10,0,0"/>
                    <local:CustomBorderEntry x:Name="txtPassword" HorizontalOptions="FillAndExpand"
                           HeightRequest="38" Margin="0,5,0,0"
                           BackgroundColor="#e5f8fc" FontSize="16"
                           TextColor ="#201f1f"
                           HorizontalTextAlignment="Start" IsPassword="true"/>
                    <Label Text="Event Code" HorizontalOptions="Start" TextColor="#e5f8fc" FontSize="20" Margin="0,10,0,0"/>
                    <local:CustomBorderEntry x:Name="txtEventCode" HorizontalOptions="FillAndExpand"
                           HeightRequest="36" Margin="0,5,0,0"
                           BackgroundColor="#e5f8fc" FontSize="16"
                           TextColor ="#201f1f"
                           HorizontalTextAlignment="Start"/>
                    <StackLayout Margin="0,20,0,0" Padding="0,1,0,0" BackgroundColor="#e5f8fc" HorizontalOptions="FillAndExpand" HeightRequest="45">
                        <local:GradientStack StartColor="#2c7f9d" EndColor="#0e5a8c" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" x:Name="slLogin">
                            <Label Text="Log in" FontSize="20" TextColor="#e5f8fc" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
                        </local:GradientStack>
                    </StackLayout>
                </local:GradientStack>
            </ScrollView>
        </StackLayout>
    </AbsoluteLayout>

答案 1 :(得分:0)

为避免重绘过程中上述解决方案中出现空异常,您需要确保检查Sublayers属性是否为null,如下所示:

if (Layer.Sublayers?[0] is CAGradientLayer)
{
    Layer.ReplaceSublayer(Layer.Sublayers[0], gradientLayer);
}
else
{
    Layer.InsertSublayer(gradientLayer, 0);
}