[英]Xamarin forms: Linebreak mode in stacklayout
Hi I am developing an app with Xamarin forms PCL.嗨,我正在使用 Xamarin 表单 PCL 开发一个应用程序。 I am using a stacklayout with horizontal orientation in which I am using a lots of button.
我正在使用水平方向的堆栈布局,其中我使用了很多按钮。 But buttons are cutting off since they go beyong stacklayouts width.
但是按钮正在切断,因为它们超出了堆栈布局的宽度。 and I don't want to use scrollview.
我不想使用滚动视图。 I want them to go to new line as soon as their is no space in first line of stacklayout.
我希望他们在 stacklayout 的第一行没有空间时立即转到新行。
Is there any linebreak kind of property for stacklayout? stacklayout 是否有任何换行类型的属性? How to achieve this?
如何实现这一目标?
What you want is a WrapLayout
you can use the custom control here你想要的是一个
WrapLayout
你可以在这里使用自定义控件
Which I will also post here incase the link breaks:我也会在这里发布以防链接中断:
using System;
using System.Linq;
using System.Collections.Generic;
namespace Xamarin.Forms
{
/// <summary>
/// New WrapLayout
/// </summary>
/// <author>Jason Smith</author>
public class WrapLayout : Layout<View>
{
Dictionary<View, SizeRequest> layoutCache = new Dictionary<View, SizeRequest> ();
/// <summary>
/// Backing Storage for the Spacing property
/// </summary>
public static readonly BindableProperty SpacingProperty =
BindableProperty.Create<WrapLayout, double> (w => w.Spacing, 5,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapLayout)bindable).layoutCache.Clear());
/// <summary>
/// Spacing added between elements (both directions)
/// </summary>
/// <value>The spacing.</value>
public double Spacing {
get { return (double)GetValue (SpacingProperty); }
set { SetValue (SpacingProperty, value); }
}
public WrapLayout ()
{
VerticalOptions = HorizontalOptions = LayoutOptions.FillAndExpand;
}
protected override void OnChildMeasureInvalidated ()
{
base.OnChildMeasureInvalidated ();
layoutCache.Clear ();
}
protected override SizeRequest OnSizeRequest (double widthConstraint, double heightConstraint)
{
double lastX;
double lastY;
var layout = NaiveLayout (widthConstraint, heightConstraint, out lastX, out lastY);
return new SizeRequest (new Size (lastX, lastY));
}
protected override void LayoutChildren (double x, double y, double width, double height)
{
double lastX, lastY;
var layout = NaiveLayout (width, height, out lastX, out lastY);
foreach (var t in layout) {
var offset = (int) ((width - t.Last ().Item2.Right) / 2);
foreach (var dingus in t) {
var location = new Rectangle(dingus.Item2.X + x + offset, dingus.Item2.Y + y, dingus.Item2.Width, dingus.Item2.Height);
LayoutChildIntoBoundingRegion (dingus.Item1, location);
}
}
}
private List<List<Tuple<View, Rectangle>>> NaiveLayout (double width, double height, out double lastX, out double lastY)
{
double startX = 0;
double startY = 0;
double right = width;
double nextY = 0;
lastX = 0;
lastY = 0;
var result = new List<List<Tuple<View, Rectangle>>> ();
var currentList = new List<Tuple<View, Rectangle>> ();
foreach (var child in Children) {
SizeRequest sizeRequest;
if (!layoutCache.TryGetValue (child, out sizeRequest)) {
layoutCache[child] = sizeRequest = child.GetSizeRequest (double.PositiveInfinity, double.PositiveInfinity);
}
var paddedWidth = sizeRequest.Request.Width + Spacing;
var paddedHeight = sizeRequest.Request.Height + Spacing;
if (startX + paddedWidth > right) {
startX = 0;
startY += nextY;
if (currentList.Count > 0) {
result.Add (currentList);
currentList = new List<Tuple<View, Rectangle>> ();
}
}
currentList.Add (new Tuple<View, Rectangle> (child, new Rectangle (startX, startY, sizeRequest.Request.Width, sizeRequest.Request.Height)));
lastX = Math.Max (lastX, startX + paddedWidth);
lastY = Math.Max (lastY, startY + paddedHeight);
nextY = Math.Max (nextY, paddedHeight);
startX += paddedWidth;
}
result.Add (currentList);
return result;
}
}
/// <summary>
/// Simple Layout panel which performs wrapping on the boundaries.
/// </summary>
public class WrapLayoutOld : Layout<View>
{
/// <summary>
/// Backing Storage for the Orientation property
/// </summary>
public static readonly BindableProperty OrientationProperty =
BindableProperty.Create<WrapLayoutOld, StackOrientation> (w => w.Orientation, StackOrientation.Vertical,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapLayoutOld)bindable).OnSizeChanged ());
/// <summary>
/// Orientation (Horizontal or Vertical)
/// </summary>
public StackOrientation Orientation {
get { return (StackOrientation)GetValue (OrientationProperty); }
set { SetValue (OrientationProperty, value); }
}
/// <summary>
/// Backing Storage for the Spacing property
/// </summary>
public static readonly BindableProperty SpacingProperty =
BindableProperty.Create<WrapLayoutOld, double> (w => w.Spacing, 6,
propertyChanged: (bindable, oldvalue, newvalue) => ((WrapLayoutOld)bindable).OnSizeChanged());
/// <summary>
/// Spacing added between elements (both directions)
/// </summary>
/// <value>The spacing.</value>
public double Spacing {
get { return (double)GetValue (SpacingProperty); }
set { SetValue (SpacingProperty, value); }
}
/// <summary>
/// This is called when the spacing or orientation properties are changed - it forces
/// the control to go back through a layout pass.
/// </summary>
private void OnSizeChanged()
{
this.ForceLayout();
}
//http://forums.xamarin.com/discussion/17961/stacklayout-with-horizontal-orientation-how-to-wrap-vertically#latest
// protected override void OnPropertyChanged
// (string propertyName = null)
// {
// base.OnPropertyChanged(propertyName);
// if ((propertyName == WrapLayout.OrientationProperty.PropertyName) ||
// (propertyName == WrapLayout.SpacingProperty.PropertyName)) {
// this.OnSizeChanged();
// }
// }
/// <summary>
/// This method is 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.Vertical
? DoVerticalMeasure(internalWidth, internalHeight)
: DoHorizontalMeasure(internalWidth, internalHeight);
}
/// <summary>
/// Does the vertical measure.
/// </summary>
/// <returns>The vertical measure.</returns>
/// <param name="widthConstraint">Width constraint.</param>
/// <param name="heightConstraint">Height constraint.</param>
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);
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; // via MitchMilam
}
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.Vertical) {
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;
}
}
}
}
}
Nowadays you can use FlexLayout现在你可以使用FlexLayout
<FlexLayout Direction="Row" Wrap="Wrap" AlignItems="Center" JustifyContent="SpaceEvenly">
<StackLayout Orientation="Vertical" FlexLayout.Basis="50%">
<Label Text="Open" HorizontalOptions="Center" TextColor="Black"/>
</StackLayout>
<FlexLayout>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.