我希望有一个Xamarin.Forms ListView从下到上开始显示其元素,以便当项目很少时,元素显示在ListView的底部。请参阅图像以获取解释。这可以不用手动设置ListView的HeightRequest吗? (如果需要手动设置HeightRequest,当我使用HasUnevenRows=true
时如何计算ListView的子元素的高度?)
这就是我想要的样子(左边几个项目,右边有很多项目);
作为参考,以下是当项目很少时ListView正常工作的方式:
答案 0 :(得分:3)
如果ListView
不是必需的,并且您只需要具有模板支持的可重复控制 - 您可以使用ItemsControl
。由于它使用StackLayout
作为其面板,因此它只会扩展到所需的高度。所以,你不需要计算它的高度。 请注意ItemsControl
具有非常基本的虚拟化行为(回收) - 因此,如果您有很多项目,那么您将不得不修改控件以支持虚拟化。
其次,您可以将Grid
扩展为根据底部内容大小自动将第二个RowDefinition
设置为Auto
或Star
。即默认情况下将其保留为Auto
,但如果内容大小超过视口高度的50%,则将RowDefinition
重置为Star
。例如,您可以将自定义SplitterGrid
创建为:
public class SplitterGrid : Grid
{
public SplitterGrid()
{
RowDefinitions = new RowDefinitionCollection()
{
new RowDefinition { Height = GridLength.Star },
new RowDefinition { Height = GridLength.Auto }
};
}
void Content2_SizeChanged(object sender, EventArgs e)
{
if (Height == 0 && Width == 0)
return;
Content2.SizeChanged -= Content2_SizeChanged;
if (Content2.Height > Height / 2)
RowDefinitions[1].Height = GridLength.Star;
else
RowDefinitions[1].Height = GridLength.Auto;
}
public static readonly BindableProperty Content1Property =
BindableProperty.Create(
"Content1", typeof(View), typeof(SplitterGrid),
defaultValue: null, propertyChanged: OnContent1Changed);
public View Content1
{
get { return (View)GetValue(Content1Property); }
set { SetValue(Content1Property, value); }
}
private static void OnContent1Changed(BindableObject bindable, object oldValue, object newValue)
{
((SplitterGrid)bindable).OnContent1ChangedImpl((View)oldValue, (View)newValue);
}
void OnContent1ChangedImpl(View oldValue, View newValue)
{
if (oldValue == null)
Children.Add(Content1);
}
public static readonly BindableProperty Content2Property =
BindableProperty.Create(
"Content2", typeof(View), typeof(SplitterGrid),
defaultValue: null, propertyChanged: OnContent2Changed);
public View Content2
{
get { return (View)GetValue(Content2Property); }
set { SetValue(Content2Property, value); }
}
private static void OnContent2Changed(BindableObject bindable, object oldValue, object newValue)
{
((SplitterGrid)bindable).OnContent2ChangedImpl((View)oldValue, (View)newValue);
}
void OnContent2ChangedImpl(View oldValue, View newValue)
{
if (oldValue == null)
{
Children.Add(Content2);
Content2.SizeChanged += Content2_SizeChanged;
Grid.SetRow(Content2, 1);
}
else
Content2.SizeChanged -= Content2_SizeChanged;
}
}
并且,用法看起来像:
<local:SplitterGrid Margin="0,20,0,0">
<local:SplitterGrid.Content1>
<ContentView Padding="10" BackgroundColor="#E4E4E4">
<Label Text="This page contains about 3 items." />
</ContentView>
</local:SplitterGrid.Content1>
<local:SplitterGrid.Content2>
<ScrollView VerticalOptions="End">
<local:ItemsControl>
<local:ItemsControl.ItemTemplate>
<DataTemplate>
<Label FontAttributes="Bold" FontSize="40" Text="{Binding .}" />
</DataTemplate>
</local:ItemsControl.ItemTemplate>
<local:ItemsControl.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Item 1</x:String>
<x:String>Item 2</x:String>
<x:String>Item 3</x:String>
</x:Array>
</local:ItemsControl.ItemsSource>
</local:ItemsControl>
</ScrollView>
</local:SplitterGrid.Content2>
</local:SplitterGrid>
答案 1 :(得分:0)
我会选择一个网格,其中定义了两行,其中一行设置为“*”,或者您想要的高度为像素,底部一行设置为“Auto”,listview VerticalOptions设置为“End”。