集合视图。 const 屏幕上的图像数量。 Xamarin 表格
CollectionView. const number of images on screen. Xamarin Forms
我有带图片的集合视图。我获得了 const number(5) 个图像以使用相对布局查看。在我的 phone 上它看起来不错。
但是在其他 phone 屏幕尺寸不同的情况下,它有比我需要的更多的图像。
如何使所有屏幕上的图像数量保持不变?
这是我的 XAML:
<Grid VerticalOptions="Center" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="44"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="44"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="44"/>
</Grid.ColumnDefinitions>
<BoxView Color="Red" Grid.Row="0" Grid.Column="0"/>
<BoxView Color="Red" Grid.Row="0" Grid.Column="2"/>
<CollectionView Grid.Row="0" Grid.Column="1" x:Name="clv" ItemsSource="{Binding ImagesArray}" HorizontalOptions="FillAndExpand" VerticalOptions="Center">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" SnapPointsAlignment="Start" SnapPointsType="Mandatory" ItemSpacing="0"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<RelativeLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image Source="{Binding ImageName}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=1, Constant=0}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.035, Constant=0}"/>
</RelativeLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
案例 A:无滚动 - 所有项目都适合。
均匀 space 项的简单方法是使用 VerticalGrid
:
<Grid ColumnSpacing="0" VerticalOptions="Center"
RowDefinitions="44" ColumnDefinitions="44,*,44">
<BoxView Color="Red" Grid.Row="0" Grid.Column="0"/>
<BoxView Color="Red" Grid.Row="0" Grid.Column="2"/>
<CollectionView Grid.Row="0" Grid.Column="1" x:Name="clv" ItemsSource="{Binding ImagesArray}"
ItemsLayout="VerticalGrid, 5" >
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="*,Auto,*">
<BoxView Grid.Column="1" WidthRequest="40" Color="Blue" VerticalOptions="Center"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
"VerticalGrid, 5"表示每行有5个项目。
这些项目将在 CollectionView 的宽度上均匀 spaced。
注意:ColumnSpacing="0"
在外部网格中,以最大化中间列(集合视图)可用的 space。
在 ItemTemplate 中,我使用了一个 3 列的 Grid 来使 BoxView 居中。这是必需的,因为 BoxView 想要填充网格单元格的整个宽度。其他元素可能不需要这个 - 而是尝试 HorizontalOptions=Center 或 HorizontalTextAlignment=Center(对于 Label)。
案例 B:水平滚动 - 已知项目和边框宽度。
EvenlySpaceItemsScrolling.xaml
:
<ContentPage.Content>
<Grid ColumnSpacing="0" VerticalOptions="Center"
RowDefinitions="44" ColumnDefinitions="44,*,44">
<BoxView Color="Red" Grid.Row="0" Grid.Column="0"/>
<BoxView Color="Red" Grid.Row="0" Grid.Column="2"/>
<CollectionView Grid.Row="0" Grid.Column="1" x:Name="clv" ItemsSource="{Binding ImagesArray}">
<CollectionView.ItemsLayout>
<LinearItemsLayout x:Name="MyItemsLayout" Orientation="Horizontal" ItemSpacing="10"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<BoxView WidthRequest="30" HeightRequest="30" Color="Blue" VerticalOptions="Center"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</ContentPage.Content>
EvenlySpaceItemsScrolling.xaml.cs
:
using System;
using System.Collections.ObjectModel;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TestBugs
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class EvenlySpaceItemsScrolling : ContentPage
{
const int NItemsToShow = 5;
const int ItemWidth = 30;
public EvenlySpaceItemsScrolling()
{
InitializeComponent();
BindingContext = this;
}
protected override void OnAppearing()
{
base.OnAppearing();
// If the amount of space to left and right of scrolling area is known,
// we can handle it before the page is laid out.
// See xaml: the width of left column is 44, right column is 44.
const int SubtractThisWidth = 44 + 44;
int collectionWidth = (int)ScreenLogicalWidth() - SubtractThisWidth;
SetSpacingAndMargin(NItemsToShow, ItemWidth, collectionWidth);
}
private void SetSpacingAndMargin(int nItemsToShow, int itemWidth, int collectionWidth)
{
int widthPerItem = collectionWidth / nItemsToShow;
int spacing = Math.Max(0, widthPerItem - itemWidth);
int leftMargin = spacing / 2;
this.MyItemsLayout.ItemSpacing = spacing;
this.clv.Margin = new Thickness(leftMargin, 0, 0, 0);
// --- Manually test values that work well at a specific screen width. ---
//this.MyItemsLayout.ItemSpacing = 30;
//this.clv.Margin = new Thickness(15, 0, 0, 0);
}
public static double ScreenLogicalWidth()
{
return DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Density;
}
// For demo, this is only used to get a count of items.
// Replace with your actual source.
public ObservableCollection<Model> ImagesArray { get; set; } = new ObservableCollection<Model> {
new Model(),
new Model(),
new Model(),
new Model(),
new Model(),
};
}
}
案例 C:水平滚动 - 测量集合宽度。
EvenlySpaceItemsScrolling.xaml
- 与案例 B 相同。
EvenlySpaceItemsScrolling.xaml.cs
- 参见案例 B,但删除 OnAppearing
中的代码并添加:
protected override void LayoutChildren(double x, double y, double width, double height)
{
base.LayoutChildren(x, y, width, height);
// Dynamically calculate based on collection width.
int collectionWidth = (int)this.clv.Width;
SetSpacingAndMargin(NItemsToShow, ItemWidth, collectionWidth);
}
我有带图片的集合视图。我获得了 const number(5) 个图像以使用相对布局查看。在我的 phone 上它看起来不错。
这是我的 XAML:
<Grid VerticalOptions="Center" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="44"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="44"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="44"/>
</Grid.ColumnDefinitions>
<BoxView Color="Red" Grid.Row="0" Grid.Column="0"/>
<BoxView Color="Red" Grid.Row="0" Grid.Column="2"/>
<CollectionView Grid.Row="0" Grid.Column="1" x:Name="clv" ItemsSource="{Binding ImagesArray}" HorizontalOptions="FillAndExpand" VerticalOptions="Center">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" SnapPointsAlignment="Start" SnapPointsType="Mandatory" ItemSpacing="0"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<RelativeLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image Source="{Binding ImageName}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=1, Constant=0}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.035, Constant=0}"/>
</RelativeLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
案例 A:无滚动 - 所有项目都适合。
均匀 space 项的简单方法是使用 VerticalGrid
:
<Grid ColumnSpacing="0" VerticalOptions="Center"
RowDefinitions="44" ColumnDefinitions="44,*,44">
<BoxView Color="Red" Grid.Row="0" Grid.Column="0"/>
<BoxView Color="Red" Grid.Row="0" Grid.Column="2"/>
<CollectionView Grid.Row="0" Grid.Column="1" x:Name="clv" ItemsSource="{Binding ImagesArray}"
ItemsLayout="VerticalGrid, 5" >
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="*,Auto,*">
<BoxView Grid.Column="1" WidthRequest="40" Color="Blue" VerticalOptions="Center"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
"VerticalGrid, 5"表示每行有5个项目。 这些项目将在 CollectionView 的宽度上均匀 spaced。
注意:ColumnSpacing="0"
在外部网格中,以最大化中间列(集合视图)可用的 space。
在 ItemTemplate 中,我使用了一个 3 列的 Grid 来使 BoxView 居中。这是必需的,因为 BoxView 想要填充网格单元格的整个宽度。其他元素可能不需要这个 - 而是尝试 HorizontalOptions=Center 或 HorizontalTextAlignment=Center(对于 Label)。
案例 B:水平滚动 - 已知项目和边框宽度。
EvenlySpaceItemsScrolling.xaml
:
<ContentPage.Content>
<Grid ColumnSpacing="0" VerticalOptions="Center"
RowDefinitions="44" ColumnDefinitions="44,*,44">
<BoxView Color="Red" Grid.Row="0" Grid.Column="0"/>
<BoxView Color="Red" Grid.Row="0" Grid.Column="2"/>
<CollectionView Grid.Row="0" Grid.Column="1" x:Name="clv" ItemsSource="{Binding ImagesArray}">
<CollectionView.ItemsLayout>
<LinearItemsLayout x:Name="MyItemsLayout" Orientation="Horizontal" ItemSpacing="10"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<BoxView WidthRequest="30" HeightRequest="30" Color="Blue" VerticalOptions="Center"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</ContentPage.Content>
EvenlySpaceItemsScrolling.xaml.cs
:
using System;
using System.Collections.ObjectModel;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TestBugs
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class EvenlySpaceItemsScrolling : ContentPage
{
const int NItemsToShow = 5;
const int ItemWidth = 30;
public EvenlySpaceItemsScrolling()
{
InitializeComponent();
BindingContext = this;
}
protected override void OnAppearing()
{
base.OnAppearing();
// If the amount of space to left and right of scrolling area is known,
// we can handle it before the page is laid out.
// See xaml: the width of left column is 44, right column is 44.
const int SubtractThisWidth = 44 + 44;
int collectionWidth = (int)ScreenLogicalWidth() - SubtractThisWidth;
SetSpacingAndMargin(NItemsToShow, ItemWidth, collectionWidth);
}
private void SetSpacingAndMargin(int nItemsToShow, int itemWidth, int collectionWidth)
{
int widthPerItem = collectionWidth / nItemsToShow;
int spacing = Math.Max(0, widthPerItem - itemWidth);
int leftMargin = spacing / 2;
this.MyItemsLayout.ItemSpacing = spacing;
this.clv.Margin = new Thickness(leftMargin, 0, 0, 0);
// --- Manually test values that work well at a specific screen width. ---
//this.MyItemsLayout.ItemSpacing = 30;
//this.clv.Margin = new Thickness(15, 0, 0, 0);
}
public static double ScreenLogicalWidth()
{
return DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Density;
}
// For demo, this is only used to get a count of items.
// Replace with your actual source.
public ObservableCollection<Model> ImagesArray { get; set; } = new ObservableCollection<Model> {
new Model(),
new Model(),
new Model(),
new Model(),
new Model(),
};
}
}
案例 C:水平滚动 - 测量集合宽度。
EvenlySpaceItemsScrolling.xaml
- 与案例 B 相同。
EvenlySpaceItemsScrolling.xaml.cs
- 参见案例 B,但删除 OnAppearing
中的代码并添加:
protected override void LayoutChildren(double x, double y, double width, double height)
{
base.LayoutChildren(x, y, width, height);
// Dynamically calculate based on collection width.
int collectionWidth = (int)this.clv.Width;
SetSpacingAndMargin(NItemsToShow, ItemWidth, collectionWidth);
}