首页 > 解决方案 > 如何使用 Xamarin 表单将图像放置在框架的一半中

问题描述

我想在我的应用程序的半帧中放置一个图像,我正在使用 xamarin 表单来执行此操作,我该怎么做

我的 Xaml

 <StackLayout HorizontalOptions = "FillAndExpand" VerticalOptions="StartAndExpand" >
        <ListView x:Name="lv_search" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" RowHeight="175" SeparatorColor="White">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <AbsoluteLayout HorizontalOptions = "FillAndExpand" VerticalOptions="StartAndExpand" >
                            <Frame BackgroundColor = "White" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" Margin="20,10,0,0"
                             HeightRequest="75" AbsoluteLayout.LayoutBounds="0.01,0.9,1,1" AbsoluteLayout.LayoutFlags="All">
                                <Image Source = "img_frm" BackgroundColor="#14559a" AbsoluteLayout.LayoutBounds="0.009,0.9,0.3,0.6" AbsoluteLayout.LayoutFlags="All"  />
                                <StackLayout Orientation = "Horizontal"  HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand">
                                    <AbsoluteLayout HorizontalOptions = "StartAndExpand" >
                                        <Image Source="ellipse_1" VerticalOptions="CenterAndExpand" HorizontalOptions="Start" AbsoluteLayout.LayoutFlags="All"
                                        AbsoluteLayout.LayoutBounds="0.01,0.4,1,1" HeightRequest="100" WidthRequest="100" BackgroundColor="White"/>
                                        <Image Source = "{Binding Image}" AbsoluteLayout.LayoutBounds="0.02,0.4,1,1" AbsoluteLayout.LayoutFlags="All"
                                           HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"  ></Image>
                                    </AbsoluteLayout>
                                    <Label x:Name="lbl_categories" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand"  Margin="10,0,0,0" 
                                      TextColor="Black"   Text="{Binding Title}" LineBreakMode="WordWrap"  HorizontalTextAlignment="Start"
                                      FontSize="Medium" FontAttributes="Bold" AbsoluteLayout.LayoutBounds="0.3,0.3,1,1" AbsoluteLayout.LayoutFlags="All"/>
                                    <Image HorizontalOptions = "EndAndExpand" VerticalOptions="Center" Source="arrow"  AbsoluteLayout.LayoutBounds="0.9,0.3,0.3,0.3"
                                      AbsoluteLayout.LayoutFlags="All" />
                                </StackLayout>
                            </Frame>
                        </AbsoluteLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        </StackLayout>

但它并没有开发出我想要的设计。

其实我想要这样的设计

在此处输入图像描述

但是我得到了这样的设计,如何将设计修改为上图

在此处输入图像描述

标签: c#listviewxamarinxamarin.forms

解决方案


我讨厌这样说,但是对于您想要达到的结果,您的 xaml 是一场噩梦。不仅因为您的可视化树中有过多的元素,还因为您在 ListView 中使用了 AbsoluteLayout。

尽管这在技术上是可行的,但它会导致您的应用程序性能下降,尤其是当您的 ListView 填充了很多项目时。

其次,为那个蓝色方块创建一个图像也是一种内存浪费,并且会导致更多的性能下降,如果您的 ListView 包含许多条目,最终可能会导致 Android 上的 OutOfMemoryExceptions。

您可以将其替换为从框视图继承的自定义视图,并使用自定义渲染器来渲染圆角。

还要避免在 ListView 中使用 StackLayout,因为它也会导致性能问题,因为 StackLayout 在布局时会进行大量计算。

正如 Dennis 已经提到的,您要走的路是使用 Grid 进行布局,请记住,添加到网格中的所有元素将按照它们在 xaml 定义中的添加顺序相互叠加。

尤其是在使用 ListViews 时,尽量少用元素,避免需要大量布局传递的元素。

尽管我在示例中没有使用它,但我想添加一些信息,即您也可以使用负边距值进行高级元素定位。

这是一个简短的示例,我一起破解:

<ListView VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" RowHeight="80">
        <ListView.ItemsSource>
            <x:Array Type="{x:Type x:String}">
                <!-- quick hack to make the list view populate items without having to write model classes -->
                <x:String>Entry 1</x:String>
                <x:String>Entry 2</x:String>
                <x:String>Entry 3</x:String>
                <x:String>Entry 4</x:String>
            </x:Array>
        </ListView.ItemsSource>
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
                        <BoxView BackgroundColor="LightGray" Margin="19,9,9,9" />
                        <Grid Margin="20,10,10,10" BackgroundColor="White">
                            <Label Text="{Binding .}" VerticalOptions="Center" FontSize="18" Margin="25,0,0,0"/>
                            <!-- insert icons, labels, etc here -->
                        </Grid>
                        <customs:RoundedBoxView BackgroundColor="DarkBlue" CornerRadius="6" WidthRequest="15" VerticalOptions="FillAndExpand" HorizontalOptions="Start" Margin="10,20,0,20" />
                </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

RoundedBoxView 类如下所示:

public class RoundedBoxView : BoxView
{
    readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(double), typeof(double), 0.0);

    public double CornerRadius
    {
        get { return (double)GetValue(CornerRadiusProperty); }
        set { SetValue(CornerRadiusProperty, value); }
    }
}

这将是 android 的自定义渲染器:

[assembly: ExportRenderer(typeof(RoundedBoxView), typeof(RoundedBoxViewRenderer))]
namespace TestApp.Droid
{
public class RoundedBoxViewRenderer : BoxRenderer
{
    public RoundedBoxViewRenderer(Context context) : base(context)
    {

    }

    protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
    {
        base.OnElementChanged(e);
        SetWillNotDraw(false);
        Invalidate();
    }

    public override void Draw(Canvas canvas)
    {
        var box = Element as RoundedBoxView;
        var rect = new Rect();
        var paint = new Paint()
        {
            Color = box.BackgroundColor.ToAndroid(),
            AntiAlias = true,
        };
        GetDrawingRect(rect);
        var radius = (float)(box.CornerRadius); 
        canvas.DrawRoundRect(new RectF(rect), radius, radius, paint);
    }
}

对于 iOS:

[assembly: ExportRenderer(typeof(RoundedBoxView), typeof(RoundedBoxViewRenderer))]
namespace TestApp.iOS
{
public class RoundedBoxViewRenderer: BoxRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
    {
        base.OnElementChanged(e);
        if (Element != null)
        {
            Layer.MasksToBounds = true;
            UpdateCornerRadius(e.NewElement as RoundedBoxView);
        }
    }

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

        if (e.PropertyName == CircleView.WidthProperty.PropertyName || e.PropertyName == CircleView.HeightProperty.PropertyName)
        {
            UpdateCornerRadius(Element as RoundedBoxView);
        }
    }

    void UpdateCornerRadius(RoundedBoxView box)
    {
        Layer.CornerRadius = (nfloat)(box.CornerRadius);

        CGRect bounds = new CGRect(0, 0, box.Width, box.Width);
        Layer.Bounds = bounds;
        Layer.Frame = bounds;
    }
}

这将呈现如下:

在此处输入图像描述}


推荐阅读