- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
标题说明了一切,我想做的是获取 View 宽度(一旦计算出来)并将其乘以 x 以创建图 block 的“页面”。然后它将位于 scrollview
中,因此我们可以左右导航。
为此,我使用了一个名为 WrapLayout
的自定义 View ,它为我完成了大部分工作。我修改了它,尝试用我自己计算的宽度覆盖它的宽度 (width * pagecount
)。
我关注的主要方法是 OnMeasure
,我相信这是针对这种情况覆盖的正确方法。
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
var pageCount = (Children.Count / (Rows * 3)) + (Children.Count % (Rows * 3) > 0 ? 1 : 0);
if (HeightRequest > 0)
heightConstraint = Math.Min(heightConstraint, HeightRequest);
double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint);
if (double.IsPositiveInfinity(widthConstraint) && double.IsPositiveInfinity(heightConstraint))
{
return new SizeRequest(Size.Zero, Size.Zero);
}
var deviceWidth = Application.Current.MainPage.Width;
return new SizeRequest(new Size(deviceWidth * pageCount, internalHeight));
}
所以我使用覆盖将 View 的大小设置为 deviceWidth * pageCount
,除了使用设备宽度不是我想要的之外,它应该使用自己计算的宽度以便此 View 可以在不拉伸(stretch)整个设备宽度的情况下使用。
在 Xamarin 计算出 View 的宽度并覆盖该值以将其替换为我自己的值,从而使 View 变大 x 倍后,我如何获取 View 的宽度?
我知道这是一个大问题,所以如果我遗漏了任何关键信息,请随时发表评论。
注意:如果对此有很好的回答,我会在可能的时候悬赏。这让我发疯!
按照评论中的要求。您可以看到图 block 已正确缩放并且 View 已扩展其宽度以允许每个 View 有 6 个图 block 。此演示是使用本文中的代码创建的(使用设备宽度,而不是 View 宽度)。
这将是一个自定义 View ,因此会有很多代码,所以请耐心等待,我将把它放在帖子的末尾以缩短问题:
public class RepeatableWrapLayout : WrapLayoutSimple
{
public static BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof (IEnumerable), typeof (RepeatableWrapLayout), null, defaultBindingMode: BindingMode.OneWay, propertyChanged: ItemsChanged);
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
public static BindableProperty ItemTemplateProperty = BindableProperty.Create(nameof(ItemTemplate), typeof (DataTemplate), typeof (RepeatableWrapLayout), default (DataTemplate), propertyChanged: (bindable, oldValue, newValue) =>
{
var control = (RepeatableWrapLayout)bindable;
//when to occur propertychanged earlier ItemsSource than ItemTemplate, raise ItemsChanged manually
if (newValue != null && control.ItemsSource != null && !control.doneItemSourceChanged)
{
ItemsChanged(bindable, null, control.ItemsSource);
}
}
);
public DataTemplate ItemTemplate
{
get
{
return (DataTemplate)GetValue(ItemTemplateProperty);
}
set
{
SetValue(ItemTemplateProperty, value);
}
}
public static BindableProperty ItemTapCommandProperty = BindableProperty.Create(nameof(ItemTapCommand), typeof (ICommand), typeof (RepeatableWrapLayout), default (ICommand), defaultBindingMode: BindingMode.OneWay, propertyChanged: ItemTapCommandChanged);
/// <summary>
/// Command invoked when it tapped a item.
/// </summary>
public ICommand ItemTapCommand
{
get
{
return (ICommand)GetValue(ItemTapCommandProperty);
}
set
{
SetValue(ItemTapCommandProperty, value);
}
}
private bool doneItemSourceChanged = false;
private static void ItemTapCommandChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (RepeatableWrapLayout)bindable;
if (oldValue != newValue && control.ItemsSource != null)
{
UpdateCommand(control);
}
}
private static void ItemsChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (RepeatableWrapLayout)bindable;
// when to occur propertychanged earlier ItemsSource than ItemTemplate, do nothing.
if (control.ItemTemplate == null)
{
control.doneItemSourceChanged = false;
return;
}
control.doneItemSourceChanged = true;
IEnumerable newValueAsEnumerable;
try
{
newValueAsEnumerable = newValue as IEnumerable;
}
catch (Exception e)
{
throw e;
}
var oldObservableCollection = oldValue as INotifyCollectionChanged;
if (oldObservableCollection != null)
{
oldObservableCollection.CollectionChanged -= control.OnItemsSourceCollectionChanged;
}
var newObservableCollection = newValue as INotifyCollectionChanged;
if (newObservableCollection != null)
{
newObservableCollection.CollectionChanged += control.OnItemsSourceCollectionChanged;
}
control.Children.Clear();
if (newValueAsEnumerable != null)
{
foreach (var item in newValueAsEnumerable)
{
var view = CreateChildViewFor(control.ItemTemplate, item, control);
control.Children.Add(view);
}
}
if (control.ItemTapCommand != null)
{
UpdateCommand(control);
}
control.UpdateChildrenLayout();
control.InvalidateLayout();
}
private static void UpdateCommand(RepeatableWrapLayout control)
{
foreach (var view in control.Children)
{
view.GestureRecognizers.Add(new TapGestureRecognizer{Command = control.ItemTapCommand, CommandParameter = view.BindingContext, });
}
}
private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var invalidate = false;
if (e.Action == NotifyCollectionChangedAction.Replace)
{
this.Children.RemoveAt(e.OldStartingIndex);
var item = e.NewItems[e.NewStartingIndex];
var view = CreateChildViewFor(this.ItemTemplate, item, this);
if (ItemTapCommand != null)
{
view.GestureRecognizers.Add(new TapGestureRecognizer{Command = ItemTapCommand, CommandParameter = item, });
}
this.Children.Insert(e.NewStartingIndex, view);
}
else if (e.Action == NotifyCollectionChangedAction.Add)
{
if (e.NewItems != null)
{
for (var i = 0; i < e.NewItems.Count; ++i)
{
var item = e.NewItems[i];
var view = CreateChildViewFor(this.ItemTemplate, item, this);
if (ItemTapCommand != null)
{
view.GestureRecognizers.Add(new TapGestureRecognizer{Command = ItemTapCommand, CommandParameter = item, });
}
this.Children.Insert(i + e.NewStartingIndex, view);
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
if (e.OldItems != null)
{
this.Children.RemoveAt(e.OldStartingIndex);
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
this.Children.Clear();
}
else
{
return;
}
if (invalidate)
{
this.UpdateChildrenLayout();
this.InvalidateLayout();
}
}
private View CreateChildViewFor(object item)
{
this.ItemTemplate.SetValue(BindableObject.BindingContextProperty, item);
return (View)this.ItemTemplate.CreateContent();
}
private static View CreateChildViewFor(DataTemplate template, object item, BindableObject container)
{
var selector = template as DataTemplateSelector;
if (selector != null)
{
template = selector.SelectTemplate(item, container);
}
//Binding context
template.SetValue(BindableObject.BindingContextProperty, item);
return (View)template.CreateContent();
}
}
public class WrapLayoutSimple : Layout<View>
{
Dictionary<Size, LayoutData> layoutDataCache = new Dictionary<Size, LayoutData>();
#region Props
public static readonly BindableProperty RowsProperty = BindableProperty.Create("Rows", typeof (int), typeof (WrapLayout), 2, propertyChanged: (bindable, oldvalue, newvalue) =>
{
//((WrapTestLayout)bindable).InvalidateLayout();
}
);
public static readonly BindableProperty ColumnsProperty = BindableProperty.Create("Columns", typeof (int), typeof (WrapLayout), 3, propertyChanged: (bindable, oldvalue, newvalue) =>
{
// ((WrapTestLayout)bindable).InvalidateLayout();
}
);
public static readonly BindableProperty ColumnSpacingProperty = BindableProperty.Create("ColumnSpacing", typeof (double), typeof (WrapLayout), 0.00, propertyChanged: (bindable, oldvalue, newvalue) =>
{
//((WrapTestLayout)bindable).InvalidateLayout();
}
);
public static readonly BindableProperty RowSpacingProperty = BindableProperty.Create("RowSpacing", typeof (double), typeof (WrapLayout), 0.00, propertyChanged: (bindable, oldvalue, newvalue) =>
{
//((WrapTestLayout)bindable).InvalidateLayout();
}
);
public static readonly BindableProperty PagePaddingProperty = BindableProperty.Create("RowSpacing", typeof (Thickness), typeof (WrapLayout), new Thickness(0), propertyChanged: (bindable, oldvalue, newvalue) =>
{
//((WrapTestLayout)bindable).InvalidateLayout();
}
);
public double ColumnSpacing
{
set
{
SetValue(ColumnSpacingProperty, value);
}
get
{
return (double)GetValue(ColumnSpacingProperty);
}
}
public double RowSpacing
{
set
{
SetValue(RowSpacingProperty, value);
}
get
{
return (double)GetValue(RowSpacingProperty);
}
}
public int Rows
{
set
{
SetValue(RowsProperty, value);
}
get
{
return (int)GetValue(RowsProperty);
}
}
public int Columns
{
set
{
SetValue(ColumnsProperty, value);
}
get
{
return (int)GetValue(ColumnsProperty);
}
}
public Thickness PagePadding
{
set
{
SetValue(PagePaddingProperty, value);
}
get
{
return (Thickness)GetValue(PagePaddingProperty);
}
}
#endregion
public WrapLayoutSimple()
{
HorizontalOptions = LayoutOptions.FillAndExpand;
}
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
var pageCount = (Children.Count / (Rows * 3)) + (Children.Count % (Rows * 3) > 0 ? 1 : 0);
if (HeightRequest > 0)
heightConstraint = Math.Min(heightConstraint, HeightRequest);
double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint);
if (double.IsPositiveInfinity(widthConstraint) && double.IsPositiveInfinity(heightConstraint))
{
return new SizeRequest(Size.Zero, Size.Zero);
}
var deviceWidth = Application.Current.MainPage.Width;
return new SizeRequest(new Size(deviceWidth * pageCount, internalHeight));
}
protected override void LayoutChildren(double x, double y, double width, double height)
{
var PageCount = (Children.Count / (Rows * 3)) + (Children.Count % (Rows * 3) > 0 ? 1 : 0);
var pageWidth = width / PageCount;
LayoutData layoutData = GetLayoutData(pageWidth, height);
if (layoutData.VisibleChildCount == 0)
{
return;
}
double xChild = x;
double yChild = y;
int row = 0;
int column = 0;
int count = 0;
int page = 0;
int itemsPerPage = Rows * 3;
foreach (View child in Children)
{
if (!child.IsVisible)
{
continue;
}
// New page
if (count % itemsPerPage == 0 & count != 0)
{
// Add a page on
page++;
// Reset the Y so we start from the top again
yChild = y;
}
count++;
// A check for a guff width, if not use the good stuff.
// Width * page will get it to the right width
double xLocation;
if (Double.IsInfinity(pageWidth))
xLocation = 0;
else
xLocation = (pageWidth * page);
LayoutChildIntoBoundingRegion(child, new Rectangle(new Point(xChild + xLocation, yChild), layoutData.CellSize));
Debug.WriteLine("Adding child x: {0} y: {1} page: {2}", xChild + xLocation, yChild, page);
// Reset for Second row if we hit our col limit
if (++column == layoutData.Columns)
{
// Reset col
column = 0;
// Add row
row++;
// Reset the x so we start fromt he x start again (start of new row)
xChild = x;
// Add the height ready for the next placement (a row down)
yChild += layoutData.CellSize.Height;
}
else
{
// Add the width ready for the next placement
xChild += layoutData.CellSize.Width;
}
}
}
LayoutData GetLayoutData(double width, double height)
{
Debug.WriteLine("Page Width: " + width);
Size size = new Size(width, height);
// Check if cached information is available.
if (layoutDataCache.ContainsKey(size))
{
return layoutDataCache[size];
}
int visibleChildCount = 0;
Size maxChildSize = new Size();
LayoutData layoutData = new LayoutData();
// Enumerate through all the children.
foreach (View child in Children)
{
// Skip invisible children.
if (!child.IsVisible)
continue;
// Count the visible children.
visibleChildCount++;
// Get the child's requested size.
SizeRequest childSizeRequest = child.Measure(Double.PositiveInfinity, Double.PositiveInfinity);
// Accumulate the maximum child size.
maxChildSize.Width = Math.Max(maxChildSize.Width, childSizeRequest.Request.Width);
maxChildSize.Height = Math.Max(maxChildSize.Height, childSizeRequest.Request.Height);
}
if (visibleChildCount != 0)
{
// Now maximize the cell size based on the layout size.
Size cellSize = new Size();
if (Double.IsPositiveInfinity(width))
{
cellSize.Width = maxChildSize.Width;
}
else
{
cellSize.Width = width / Columns;
}
if (Double.IsPositiveInfinity(height))
{
cellSize.Height = maxChildSize.Height;
}
else
{
cellSize.Height = height / Rows;
}
layoutData = new LayoutData(visibleChildCount, cellSize, Rows, Columns);
}
layoutDataCache.Add(size, layoutData);
Debug.WriteLine("Cell Width: " + layoutData.CellSize.Width + " Height: " + layoutData.CellSize.Height);
return layoutData;
}
protected override void InvalidateLayout()
{
base.InvalidateLayout();
// Discard all layout information for children added or removed.
layoutDataCache.Clear();
}
protected override void OnChildMeasureInvalidated()
{
base.OnChildMeasureInvalidated();
// Discard all layout information for child size changed.
layoutDataCache.Clear();
}
}
<l:RepeatableWrapLayout
x:Name="rwl"
HorizontalOptions="Fill" VerticalOptions="FillAndExpand" >
<l:RepeatableWrapLayout.ItemTemplate>
<DataTemplate>
<StackLayout BackgroundColor="{Binding Color}">
<Label VerticalTextAlignment="Center" HorizontalTextAlignment="Center"
Text="{Binding Name}" />
</StackLayout>
</DataTemplate>
</l:RepeatableWrapLayout.ItemTemplate>
</l:RepeatableWrapLayout>
使用我提供的所有内容,您应该能够自己构建它以在需要时进行测试。
最佳答案
我现在找到了一些解决方法,它似乎工作得很好,所以将使用这个版本进行测试。
我在 wraplayout
上设置了一个新属性以接受其父级宽度,因为在这种情况下,父级是 ScrollView ,我们使用该 View 宽度并将其传递给 wraplayout
像这样。
public static readonly BindableProperty ParentWidthProperty = BindableProperty.Create("ParentWidth",
typeof(double),
typeof(WrapLayout),
0.00,
propertyChanged: (bindable, oldvalue, newvalue) =>
{
((RepeatableWrapLayout)bindable).SetNewWidth();
});
public double ParentWidth
{
set { SetValue(ParentWidthProperty, value); }
get { return (double)GetValue(ParentWidthProperty); }
}
使用它,我们可以在属性更改时触发事件并设置 wraplayout
的宽度。我在这里进行了一些检查,以阻止它在需要之前跳跳。
double oldParentWidth;
public void SetNewWidth()
{
var pageCount = (Children.Count / (Rows * 3)) + (Children.Count % (Rows * 3) > 0 ? 1 : 0);
if (ParentWidth > 0 && ParentWidth != oldParentWidth)
{
oldParentWidth = ParentWidth;
WidthRequest = ParentWidth * pageCount;
}
}
XAML 现在看起来像这样将父级宽度绑定(bind)到我们新创建的属性。
<Controls:RepeatableWrapLayout ParentWidth="{Binding Source={x:Reference Name=parentScrollView} ,Path=Width}" ...>
...
</Controls:RepeatableWrapLayout>
关于c# - View 根据 child 数量扩展自己的宽度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51875694/
我的收藏具有以下结构 { _id:1, parent_id:0 } { _id:2, parent_id:1 } { _id:3, parent_id:1 } { _id:4, par
到目前为止,我已经尝试过获取该对象的所有子对象,但它只带来了两个子对象。不都是 child 的 child 。我如何获取所有内容并循环获取特定名称对象 Transform[] objChild = g
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
我有一个如下表 好吧,在这个表中每个用户都有一个父用户,那么如果我们选择一个用户,那么它的 id 、子代 id 和子代子代 id 应该作为数组返回。我需要一个查询来获取 Rails 中的这些值,而不使
我需要以下代码的帮助: HTML: process process 在点击 td[class=process] 时,我需要 input[name=dat
好的,所以我从中获得了一个 PHP,该 PHP 由依赖于手头动态情况的切换循环传播(我认为)。现在,当我添加一个复选框时,我希望能够使 div 中的第一个复选框具有顶部边框和侧面,没有底部。下面的只有
我正在使用 Swift 和 Sprite Kit。我有一个名为 MrNode 的 SKNode,它有多个 SKSpriteNodes 和 SKNode 子节点。一些SKNode有子节点,而这些子节点也
对不起,这个标题太俗了,但我真的不确定如何解释这个,我是新一代的 SQL 技能由于事件记录模式而退化的人之一! 基本上我在 PostgreSQL 中有三个表 客户端(一个客户端有很多 map ) -
我有这样的简单表格: 编号 parent_id 创建于 具有父/子关系...如果一行是子行,则它有一个 parent_id,否则它的 parent_id 为 0。 现在我想选择所有没有子项(因此本身)
所以我有这样的结构: 我的问题是:如何从每个主题中删除 ID 为 3Q41X2tKUMUmiDjXL1BJon70l8n2 的每个字段。我正在考虑这样的事情: admin.database().ref
这个问题在这里已经有了答案: Change opacity on all elements except hovered one (1 个回答) 关闭 5 个月前。 因此,当鼠标悬停在 child
我需要在 Delphi 5 中创建一个 QuickReport,其布局如下: +================ | Report Header +================ +========
假设我有这样的 html: Some more detailed code.... 我想知道如何在CSS中使用“A
我有一个使用 flexbox 的类似表格的布局: +--------------+---------------+-----------------+---------------+ | 1
我有一个关联,其中 user has_many user_items 和 user_items has_many user_item_images。与一个已经退出的用户。我可以创建一个新的 user_
我想选择无序列表中的前两个列表项。我可以这样选择第一项: ul li:nth-child(1) a { background: none repeat scroll 0 0 beige; }
ul li:first-child a { border-radius: 5px 5px 0 0; } ul li:last-child a { border-radius: 0 0 5p
我有一个这样的表:
或者这些术语用于指代同一事物? 我正在尝试在我的 Win32 应用程序中实现一些显示位图图像的自定义按钮。一个教程指出我应该使用 CreateWindow() 创建子窗口。 但是,我已经从另一个关于创
我想在 jquery 中获取我的 svg 的 id,我尝试了这个 jquery,但它是未定义的。 $(event.target).children('svg').attr("id") Target.e
我是一名优秀的程序员,十分优秀!