我正在研究Xamarin表格。我需要一个渐变stacklayout视图,其宽度设置为堆栈布局,大于设备的纵向宽度。设置此宽度将确保stacklayout适合纵向视图,并且在横向中可以看到具有宽度的stacklayout。在这里,我需要一个从上到下的渐变stacklayout。我已经看到一些带有自定义渲染器的帖子,用于stacklayout,效果很好。
但是当我使用这些渲染器时,我可以看到在实时场景中将方向从纵向更改为横向时,绘制的渐变布局宽度被视为纵向宽度,其余区域为空。参见附件中的图片
肖像
[![肖像] [1] [1]
和风景
以下是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);
}
}
答案 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);
}