我在框架內有一個 flexlayout、一個網格和一個堆疊布局:
<CollectionView x:Name="collectionView"
Margin="20"
SelectionMode="Single"
SelectionChanged="OnSelectionChanged">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"
ItemSpacing="10" />
</CollectionView.ItemsLayout>
<!-- Define the appearance of each item in the list -->
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="0,10,0,0" Spacing="0">
<StackLayout Orientation="Horizontal" Margin="0">
<Label FontSize="Medium" FontAttributes="Bold" Text="{Binding Name, Mode=OneWay}" />
<Label Text="{Binding Bottle.ID, Mode=OneWay}" FontSize="Medium"
FontAttributes="Italic" VerticalTextAlignment="Center"
Margin="20,0,0,0"/>
</StackLayout>
<Frame CornerRadius="10" BorderColor="Black" IsVisible="{Binding IsConnected, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}" Padding="10">
<Label Text="not connected" FontSize="Small"/>
</Frame>
<Frame CornerRadius="10" BorderColor="Black" IsVisible="{Binding IsConnected, Mode=OneWay}" Padding="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0">
<FlexLayout BindableLayout.ItemsSource="{Binding Bottle.Components, Mode=OneWay}"
Direction="Row" JustifyContent="Start" Wrap="Wrap"
AlignItems="Center" AlignContent="Start"
>
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label FontSize="Small" Text="{Binding DisplayString}" VerticalOptions="CenterAndExpand" Margin="0,0,10,0" Padding="0"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
<StackLayout Orientation="Horizontal" IsVisible="{Binding IsConnected, Mode=OneWay}" VerticalOptions="FillAndExpand">
<Label FontSize="Small" Text="in " IsVisible="{Binding Bottle.IsCarrier, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"/>
<Label FontSize="Small" Text="{Binding Bottle.CarrierGas, Mode=OneWay}"/>
<Label FontSize="Small" Text=" 100%" IsVisible="{Binding Bottle.IsCarrier, Mode=OneWay}" />
</StackLayout>
</StackLayout>
<Label FontSize="Small" Text="(ISO)" FontAttributes="Italic" Grid.Column="1" IsVisible="False">
<Label.Triggers>
<MultiTrigger TargetType="Label">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Bottle.IsISOCertified, Mode=OneWay}" Value="True" />
<BindingCondition Binding="{Binding IsConnected, Mode=OneWay}" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="IsVisible" Value="True" />
</MultiTrigger>
</Label.Triggers>
</Label>
</Grid>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
在特定輸入資料處,flexlayout 未正確顯示(請參閱串列中的第一個元素):
如果我洗掉框架,文本顯示正確:
如果我保留框架并將 flexlayout 元素的邊距或內邊距增加一,文本將正確顯示在 2 行中。
<DataTemplate>
<Label FontSize="Small" Text="{Binding DisplayString}" VerticalOptions="CenterAndExpand" Margin="0,0,11,0"/>
</DataTemplate>
此外,如果我將字體大小增加到中等,它會正確顯示。另外,如果我不重新啟動應用程式而是讓visual studio自動更新表單,在減小字體大小后,顯示是正確的。但是,如果我重新啟動 Android Emulator,問題又會出現。
字體大小中等:
<DataTemplate>
<Label FontSize="Medium" Text="{Binding DisplayString}" VerticalOptions="CenterAndExpand" Margin="0,0,10,0"/>
</DataTemplate>
將其重置為小后,但未重新啟動應用程式:
I guess, increasing the Margin/Padding or increasing the font size or removing the frame would not work correctly on the long run, because there's always going to be some data/screen size combination which breaks the layout.
It seems to me, that the layout only fails in some corner cases. However, when the element widths ( margins) are over some limit, the flexlayout recognizes that the elements have to be displayed in 2 lines, and after that the layout is ok.
Is this a bug of xamarin/android, or is there a problem in my code? Could anyone suggest a workaround, solution, that works reliably?
Some extra information, not sure what is necessary:
- Target Android Version: Android 9.0 (API Level 28 - Pie)
- emulator: Pixel 2 Pie 9.0 - API28 1080x1920 420dpi
Edit: I also tested with 1020x1920, 1000x1920, 800x1920, 1200x1920 display size, all of them showed the same problem. So either the setting in Android Device Manager was not taken over (hw.lcd.width), or the problem is independent of the display size.
Edit2: changing the display size in Settings/Display affects the layout, and fixes it, if I set it to lower or larger. But I guess it is only changing the FontSize parameter of the labels.
While testing @ToolmakerSteve's solution, I found out, that the children bound.Width-s are higher if I remove the last item in the list (NO 2100ppm). Then I called measure for each children, and I saw, that the widths match those bound.Width-s when the last item was missing. So I ended up with this code:
//https://stackoverflow.com/a/70526712/9963147
class FlexLayoutImproveMeasure : FlexLayout
{
protected override void LayoutChildren(double x, double y, double width, double height)
{
base.LayoutChildren(x, y, width, height);
foreach (var child in Children)
{
Rectangle cb = child.Bounds;
Size s = child.Measure(double.PositiveInfinity, cb.Height).Request;
double newW = s.Width;
var childBounds2 = new Rectangle(cb.X, cb.Y, newW, cb.Height);
child.Layout(childBounds2);
}
}
}
uj5u.com熱心網友回復:
我發現FlexLayout有時沒有給每個標簽足夠的空間;標簽被截斷。
這是 FlexLayout 的一個子類,它為每個 Label 增加了少量的寬度。
FlexLayoutImproveMeasure.cs:
using Xamarin.Forms;
namespace XFSOAnswers
{
class FlexLayoutImproveMeasure : FlexLayout
{
protected override void LayoutChildren(double x, double y, double width, double height)
{
base.LayoutChildren(x, y, width, height);
//var childBoundss = new List<Rectangle>();
foreach (var child in Children)
{
Rectangle cb = child.Bounds;
// Make each child slightly wider: labels were being truncated.
// Less than 2 didn't always work. Increase as needed, up to right margin.
const int extraW = 2;
double newX = cb.X;
// TBD whether part of the problem is label that isn't pixel-aligned.
// (So far, seems more reliable to increase extraW instead.)
//MAYBE double newX = Math.Floor(cb.X);
double newW = cb.Width extraW;
// TBD whether it helps to ensure width extends to next pixel.
// (So far, seems more reliable to increase extraW instead.)
//MAYBE double newW = Math.Ceiling(cb.Width) extraW;
//double ceilingRight = Math.Ceiling(cb.X cb.Width);
//MAYBE double newW = ceilingRight - Math.Floor(cb.X) extraW;
var childBounds2 = new Rectangle(newX, cb.Y, newW, cb.Height);
child.Layout(childBounds2);
//childBoundss.Add(child.Bounds);
//childBoundss.Add(cb);
}
}
}
}
用它代替FlexLayout. 這是通過向頁面添加xmlns:宣告以訪問專案中的命名空間來完成的。這里的命名空間是XFSOAnswers. 更改xmlns:localline 以參考您將上述類放入的任何命名空間。
頁面的 XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XFSOAnswers"
x:Class="XFSOAnswers.FlexLayoutInItemTemplatePage">
<ContentPage.Content>
<StackLayout>
<!-- labels truncated at width in range 188-194 -->
<CollectionView ItemsSource="{Binding Items}"
WidthRequest="190" HorizontalOptions="Center"
Margin="20" >
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="10" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame CornerRadius="10" BorderColor="Black"
BackgroundColor="LightBlue" Padding="10">
<local:FlexLayoutImproveMeasure
Wrap="Wrap"
BindableLayout.ItemsSource="{Binding Items2}"
BackgroundColor="LightGray" >
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label FontSize="Small" Text="{Binding .}"
VerticalOptions="Start" HorizontalOptions="Start" Margin="0,0,10,0" Padding="0"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</local:FlexLayoutImproveMeasure>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
頁面后面的代碼具有系結:
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace XFSOAnswers
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FlexLayoutInItemTemplatePage : ContentPage
{
public FlexLayoutInItemTemplatePage()
{
InitializeComponent();
BindingContext = this;
}
public List<ListModel> Items { get; } = new List<ListModel> {
new ListModel(),
new ListModel(),
};
}
public class ListModel
{
public List<string> Items2 { get; } = new List<string> {
"aaa", "bbbbbbbbb", "cc", "dddd", "e",
};
}
}
Items2選擇的字串使得在 WidthRequest=190 處,“dddd”幾乎不適合第一行。使用和不使用最后的“e”進行了測驗,以查看 FlexLayout 在兩種情況下的作用。
原始 FlexLayout,截斷標簽:

使用 FlexLayoutImproveMeasure 和 extraW = 2:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/397989.html
