我正在开发一个控件,该控件可以动态地从List中生成一个网格,它应该始终显示2个项目。
现在我遇到了问题,在小型设备(例如iPhone 4s)上,每行仅显示一项。
XAML代码
<ContentPage.Content>
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Image Source="background.png" Grid.ColumnSpan="3" Grid.RowSpan="2" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Aspect="Fill" Margin="0,-10,0,0"/>
<Image Source="logo.png" Grid.Column="1" Grid.Row="0" HorizontalOptions="Center" HeightRequest="140"/>
<ScrollView Orientation="Vertical" Grid.Column="1" Grid.Row="1">
<view:WrapView Command="{Binding ModuleClickedCommand}" ItemsSource="{Binding TileItems}" Orientation="Vertical">
<view:WrapView.ItemTemplate>
<DataTemplate>
<Frame Opacity="0.7" CornerRadius="5" BackgroundColor="#dcdcdc" Margin="20,15,0,0" WidthRequest="130" HeightRequest="130" Padding="6,6,6,6">
<Frame.Effects>
<effects:TileClickRoutingEffect />
</Frame.Effects>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding ImgSource}"/>
<Label Grid.Row="1" HorizontalOptions="CenterAndExpand" FontSize="12" LineBreakMode="TailTruncation" Text="{Binding Title}" XAlign="Center"/>
</Grid>
</Frame>
</DataTemplate>
</view:WrapView.ItemTemplate>
</view:WrapView>
</ScrollView>
</Grid>
</ContentPage.Content>
控件中的高度/宽度计算
/// <summary>
/// Called during the measure pass of a layout cycle to get the desired size of an element.
/// </summary>
/// <param name="widthConstraint">The available width for the element to use.</param>
/// <param name="heightConstraint">The available height for the element to use.</param>
protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint)
{
if (WidthRequest > 0)
widthConstraint = Math.Min(widthConstraint, WidthRequest);
if (HeightRequest > 0)
heightConstraint = Math.Min(heightConstraint, HeightRequest);
double internalWidth = double.IsPositiveInfinity(widthConstraint) ? double.PositiveInfinity : Math.Max(0, widthConstraint);
double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint);
return Orientation == StackOrientation.Horizontal
? DoVerticalMeasure(internalWidth, internalHeight)
: DoHorizontalMeasure(internalWidth, internalHeight);
}
private SizeRequest DoVerticalMeasure(double widthConstraint, double heightConstraint)
{
int columnCount = 1;
double width = 0;
double height = 0;
double minWidth = 0;
double minHeight = 0;
double heightUsed = 0;
foreach (var item in Children)
{
var size = item.GetSizeRequest(widthConstraint, heightConstraint);
width = Math.Max(width, size.Request.Width);
var newHeight = height + size.Request.Height + Spacing;
if (newHeight > heightConstraint)
{
columnCount++;
heightUsed = Math.Max(height, heightUsed);
height = size.Request.Height;
}
else
height = newHeight;
minHeight = Math.Max(minHeight, size.Minimum.Height);
minWidth = Math.Max(minWidth, size.Minimum.Width);
}
if (columnCount > 1)
{
height = Math.Max(height, heightUsed);
width *= columnCount; // take max width
}
return new SizeRequest(new Size(width, height), new Size(minWidth, minHeight));
}
/// <summary>
/// Does the horizontal measure.
/// </summary>
/// <returns>The horizontal measure.</returns>
/// <param name="widthConstraint">Width constraint.</param>
/// <param name="heightConstraint">Height constraint.</param>
private SizeRequest DoHorizontalMeasure(double widthConstraint, double heightConstraint)
{
int rowCount = 1;
double width = 0;
double height = 0;
double minWidth = 0;
double minHeight = 0;
double widthUsed = 0;
foreach (var item in Children)
{
var size = item.GetSizeRequest(widthConstraint, heightConstraint);
// Wenn width*2 nicht mehr in widthContraint passt, dann muss die breite händisch durch /2.5 gesetzt werden. Solle dies nicht der fall sein: ganz normal weitermachen
//TODO size.Request.Width evtl anpassen
height = Math.Max(height, size.Request.Height);
var newWidth = width + size.Request.Width + Spacing;
if (newWidth > widthConstraint)
{
rowCount++;
widthUsed = Math.Max(width, widthUsed);
width = size.Request.Width;
}
else
width = newWidth;
minHeight = Math.Max(minHeight, size.Minimum.Height);
minWidth = Math.Max(minWidth, size.Minimum.Width);
}
if (rowCount > 1)
{
width = Math.Max(width, widthUsed);
height = (height + Spacing) * rowCount - Spacing;
}
return new SizeRequest(new Size(width, height), new Size(minWidth, minHeight));
}
/// <summary>
/// Positions and sizes the children of a Layout.
/// </summary>
/// <param name="x">A value representing the x coordinate of the child region bounding box.</param>
/// <param name="y">A value representing the y coordinate of the child region bounding box.</param>
/// <param name="width">A value representing the width of the child region bounding box.</param>
/// <param name="height">A value representing the height of the child region bounding box.</param>
protected override void LayoutChildren(double x, double y, double width, double height)
{
if (Orientation == StackOrientation.Horizontal)
{
double colWidth = 0;
double yPos = y, xPos = x;
foreach (var child in Children.Where(c => c.IsVisible))
{
var request = child.GetSizeRequest(width, height);
double childWidth = request.Request.Width;
double childHeight = request.Request.Height;
colWidth = Math.Max(colWidth, childWidth);
if (yPos + childHeight > height)
{
yPos = y;
xPos += colWidth + Spacing;
colWidth = 0;
}
var region = new Rectangle(xPos, yPos, childWidth, childHeight);
LayoutChildIntoBoundingRegion(child, region);
yPos += region.Height + Spacing;
}
}
else
{
double rowHeight = 0;
double yPos = y, xPos = x;
foreach (var child in Children.Where(c => c.IsVisible))
{
var request = child.GetSizeRequest(width, height);
double childWidth = request.Request.Width;
double childHeight = request.Request.Height;
rowHeight = Math.Max(rowHeight, childHeight);
if (xPos + childWidth > width)
{
xPos = x;
yPos += rowHeight + Spacing;
rowHeight = 0;
}
var region = new Rectangle(xPos, yPos, childWidth, childHeight);
LayoutChildIntoBoundingRegion(child, region);
xPos += region.Width + Spacing;
}
}
}
我现在的问题是,是否有可能根据设备的分辨率计算一帧的大小?您有解决该问题的想法吗?您是否必须处理类似的问题? 感谢您的帮助。