C# UIScrollView混合布局方法的问题
我正试着跟着你走 我见过其他类似的问题 我不确定这是否是我需要的 请理解,我既不使用故事板也不使用XIB。 我的所有视图都是使用Xamarin.iOS中的c#以编程方式创建的。这与目标C代码非常相似 像许多其他人一样,我找不到一种方法让我的滚动视图真正滚动 因此,在我的主视图控制器中,ViewDidLoad()中有以下内容: 没有什么特别的,我创建了我的UIScrollView,并将其添加为主视图的子视图。创建UIRefresh控件并将其添加到滚动视图。创建一个普通UIView并将其添加到UIScrollView中,以便放置所有我的子视图 因为我使用的是AutoLayout,所以ScrollView被锚定在主视图的约束范围内 现在,在ViewWillAppease()中,我将创建添加到普通UIView中的卡片视图。这些卡片视图使用自动布局相互堆叠,第一张卡片被锚定到容器视图的顶部、前导和尾随锚定 这些卡片中的所有内容都使用自动布局,基本上可以堆叠所有内容C# UIScrollView混合布局方法的问题,c#,ios,xamarin.ios,ios-autolayout,C#,Ios,Xamarin.ios,Ios Autolayout,我正试着跟着你走 我见过其他类似的问题 我不确定这是否是我需要的 请理解,我既不使用故事板也不使用XIB。 我的所有视图都是使用Xamarin.iOS中的c#以编程方式创建的。这与目标C代码非常相似 像许多其他人一样,我找不到一种方法让我的滚动视图真正滚动 因此,在我的主视图控制器中,ViewDidLoad()中有以下内容: 没有什么特别的,我创建了我的UIScrollView,并将其添加为主视图的子视图。创建UIRefresh控件并将其添加到滚动视图。创建一个普通UIView并将其添加到UIS
public UIView BuildQOLCard()
{
CardView qolCard = new CardView();
_scrollViewContainer.AddSubview(qolCard);
qolCard.TranslatesAutoresizingMaskIntoConstraints = false;
qolCard.CornerRadius = 5f;
qolCard.ShadowOffsetHeight = 0;
qolCard.ShadowOffsetWidth = 0;
qolCard.BackgroundColor = UIColor.White;
...
qolCard.Anchor(leading: _scrollViewContainer.LeadingAnchor, trailing: _scrollViewContainer.TrailingAnchor, top: _scrollViewContainer.TopAnchor, padding: new UIEdgeInsets(10f, 10f, 10f, 10f));
return qolCard;
}
当然,容器视图不会神奇地知道如何调整自身大小。所以我必须给它一个尺寸,否则我什么也看不见
所以我像这样制作了一个助手:
public void SizeScrollViewContentSize()
{
nfloat scrollViewHeight = 0.0f;
foreach (UIView view in this._scrollViewContainer.Subviews)
{
scrollViewHeight += view.Frame.Size.Height;
}
this._scrollViewContainer.Frame = new CGRect(0, 0, this._scrollView.Frame.Width, scrollViewHeight);
}
但我似乎不知道何时调用它,因为子视图在这里,但它们的大小未知。我尝试从ViewDidLayoutSubviews()调用它
谢谢你的帮助
编辑:对接受的答案应用te建议,导致启用滚动,但滚动视图始终返回顶部 下面是当前的代码:
public override void ViewDidLoad()
{
base.ViewDidLoad();
_scrollView = new UIScrollView
{
ShowsHorizontalScrollIndicator = false,
TranslatesAutoresizingMaskIntoConstraints = false
};
if (!UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
_scrollView.AlwaysBounceVertical = true;
_scrollView.Bounces = true;
}
_refreshControl = new UIRefreshControl { TranslatesAutoresizingMaskIntoConstraints = false };
_refreshControl.Enabled = true;
_refreshControl.ValueChanged -= RefreshControl_ValueChanged;
_refreshControl.ValueChanged += RefreshControl_ValueChanged;
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
_scrollView.RefreshControl = _refreshControl;
}
else
{
_scrollView.AddSubview(_refreshControl);
}
this.View.AddSubview(_scrollView);
_scrollViewContainer = new UIView { TranslatesAutoresizingMaskIntoConstraints = false };
_scrollView.AddSubview(_scrollViewContainer);
_scrollView.Anchor(top: this.View.SaferAreaLayoutGuide().TopAnchor, leading: this.View.LeadingAnchor, bottom: this.View.SaferAreaLayoutGuide().BottomAnchor, trailing: this.View.TrailingAnchor);
// Only define the width of the container
_scrollViewContainer.TopAnchor.ConstraintEqualTo(_scrollView.TopAnchor).Active = true;
_scrollViewContainer.LeadingAnchor.ConstraintEqualTo(_scrollView.LeadingAnchor).Active = true;
_scrollViewContainer.WidthAnchor.ConstraintEqualTo(_scrollView.WidthAnchor).Active = true;
}
第一张牌:
CardView qolCard = new CardView();
_scrollViewContainer.AddSubview(qolCard);
qolCard.TranslatesAutoresizingMaskIntoConstraints = false;
qolCard.CornerRadius = 5f;
qolCard.ShadowOffsetHeight = 0;
qolCard.ShadowOffsetWidth = 0;
qolCard.BackgroundColor = UIColor.White;
...
qolCard.Anchor(leading: _scrollViewContainer.LeadingAnchor, trailing: _scrollViewContainer.TrailingAnchor, top: _scrollViewContainer.TopAnchor, padding: new UIEdgeInsets(10f, 10f, 10f, 10f));
卡片2:
CardView goalsCard = new CardView();
_scrollViewContainer.AddSubview(goalsCard);
goalsCard.TranslatesAutoresizingMaskIntoConstraints = false;
goalsCard.CornerRadius = 5f;
goalsCard.ShadowOffsetHeight = 0;
goalsCard.ShadowOffsetWidth = 0;
goalsCard.BackgroundColor = UIColor.White;
...
// Top should be constrained to the previous CardView's Bottom
goalsCard.Anchor(leading: _scrollViewContainer.LeadingAnchor, trailing: _scrollViewContainer.TrailingAnchor, top: qolCard.BottomAnchor,padding: new UIEdgeInsets(10f, 10f, 10f, 10f));
最终锚定:
// constraint the last card bottom to the bottom of the scrollview container
goalsCard.Anchor(bottom: context._scrollViewContainer.BottomAnchor);
锚辅助对象:
internal static void Anchor(this UIView uIView, NSLayoutYAxisAnchor top = null, NSLayoutXAxisAnchor leading = null, NSLayoutYAxisAnchor bottom = null, NSLayoutXAxisAnchor trailing = null, UIEdgeInsets padding = default, CGSize size = default)
{
uIView.TranslatesAutoresizingMaskIntoConstraints = false;
if (top != null)
{
uIView.TopAnchor.ConstraintEqualTo(top, padding.Top).Active = true;
}
if (leading != null)
{
uIView.LeadingAnchor.ConstraintEqualTo(leading, padding.Left).Active = true;
}
if (bottom != null)
{
uIView.BottomAnchor.ConstraintEqualTo(bottom, -padding.Bottom).Active = true;
}
if (trailing != null)
{
uIView.TrailingAnchor.ConstraintEqualTo(trailing, -padding.Right).Active = true;
}
if (size.Width != 0)
{
uIView.WidthAnchor.ConstraintEqualTo(size.Width).Active = true;
}
if (size.Height != 0)
{
uIView.HeightAnchor.ConstraintEqualTo(size.Height).Active = true;
}
}
滚动视图需要定义其框架,需要定义其内容。如果内容约束正确,则滚动是自动的 我将一步一步地使用故事板,这样我们就可以看到发生了什么。当我们通过代码来实现它时,绝对没有什么不同 从视图控制器开始,添加一个滚动视图,并将其约束到所有四个面(我给了它一个绿色背景,以便我们可以看到它): 现在,我们添加一个“容器”视图(青色背景),并将所有4个边约束到滚动视图: 如果运行此操作,我们会看到: 这是因为“容器”没有宽度或高度。它的前导/尾随/顶部/底部约束定义了滚动视图的内容 因此,让我们将其约束为等宽度和等高度到滚动视图: 运行它,我们可以看到: 这很好,除了。。。它永远不会滚动,因为它与滚动视图的高度相同 因此,我删除了等高,因为我希望容器的内容确定其高度 我添加了一个“cardwiew”,并将其顶部/前导/尾随约束设置为“container”的顶部/前导/尾随,其中10点为“padding”,高度为100。我还为“container”(容器)的底部(+10)提供了一个底部约束,该约束将“拉动容器底部”,使其在CardView底部下方10点处: 导致: 现在,我添加了第二个CardView,将前导/尾随约束约束约束到容器的前导/尾随,具有10点“padding”,高度为100。我将其顶部约束设置为CardView-1(+10)的底部,并将其底部约束为“容器”(+10)的底部: 不幸的是,我们现在有一个来自CardView-1底部的10 pt约束和一个来自CardView-2底部的10 pt约束-当然,这不会起作用 因此,让我们从CardView-1中删除“从底部到超级视图”的约束 我们得到这个: 让我们为更多的卡片视图重复这些步骤,每次将前导/尾随约束为“容器”,高度为100,从上一张卡片视图的顶部到底部。。。然后仅将最后一个卡片视图的底部约束到“容器”的底部: 耶!我们可以滚动: 通过代码执行此操作只需记住,每个CardView的顶部都应约束到上一个CardView的底部——除了第一个卡,您将其约束到“容器”的顶部和最后一个卡,您将其约束到“容器”的底部 所有这些都是通过自动布局完成的。无需执行任何“计算高度和设置框架”代码
作为补充说明,您可以使用StackView并消除其中的大部分:
- 忘记“容器”
- 将堆栈视图添加到滚动视图
- 轴:垂直,间距:10
- 使用10 pts填充将堆栈视图的所有4个边约束到滚动视图
- 为堆栈视图提供一个宽度约束,该约束等于滚动视图宽度-20(对于每侧的10点填充)
还有。。。。完成了 谢谢你的解释。只是一个快速更新,让你知道它滚动,但它总是反弹回顶部。有什么问题吗?@OlivierMATROT-您必须向我展示您正在使用的代码,以便找出原因。@OlivierMATROT-可能有一些问题。。。您是否每次拉刷新时都会添加一张新的“卡”?如果是这样,当您向新添加的卡添加底部锚定时,您是否正在移除上一张卡的底部锚定?另外,当刷新控件结束刷新时,它会将内容滚动回顶部。。。我不使用Xamarin/C#,所以我不能给你一个完整的例子(我可以给你一个Swift或Objective-C)当我拉刷新时,我从scrollViewContainer中删除所有子视图(卡片),并用更新的数据将它们添加回来。问题是我甚至不能滚动到机器人
internal static void Anchor(this UIView uIView, NSLayoutYAxisAnchor top = null, NSLayoutXAxisAnchor leading = null, NSLayoutYAxisAnchor bottom = null, NSLayoutXAxisAnchor trailing = null, UIEdgeInsets padding = default, CGSize size = default)
{
uIView.TranslatesAutoresizingMaskIntoConstraints = false;
if (top != null)
{
uIView.TopAnchor.ConstraintEqualTo(top, padding.Top).Active = true;
}
if (leading != null)
{
uIView.LeadingAnchor.ConstraintEqualTo(leading, padding.Left).Active = true;
}
if (bottom != null)
{
uIView.BottomAnchor.ConstraintEqualTo(bottom, -padding.Bottom).Active = true;
}
if (trailing != null)
{
uIView.TrailingAnchor.ConstraintEqualTo(trailing, -padding.Right).Active = true;
}
if (size.Width != 0)
{
uIView.WidthAnchor.ConstraintEqualTo(size.Width).Active = true;
}
if (size.Height != 0)
{
uIView.HeightAnchor.ConstraintEqualTo(size.Height).Active = true;
}
}