如何使用 AutoLayout (iOS/Xamarin.iOS) 使 ScrollView 适合其内容?

Posted

技术标签:

【中文标题】如何使用 AutoLayout (iOS/Xamarin.iOS) 使 ScrollView 适合其内容?【英文标题】:How to make ScrollView fit its content using AutoLayout (iOS/Xamarin.iOS)? 【发布时间】:2016-09-26 13:51:28 【问题描述】:

目前我正在尝试使用 ios 10.0 进行此操作

假设我有一个带有一个子子视图的 ScrollView(这是一个由其他三个视图组成的视图)。 架构如下所示:

UIView
->ScrollView
-->View Container
--->TopView
--->MiddleView
--->BottomView 

TopView 和 MiddleView 都具有动态高度(根据内容可能会更小或更大)。

我相信我已经正确设置了约束(我一直在关注本教程 - https://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/)

Here is my view heirarchy

问题本身如下所示: BottomView 被截断(或者换句话说,不想增长)。虽然显示了 BottomView 的内容 - 它显示在 View Container 的边界下方。所以无法看到BottomView的所有子视图和控件(因为滚动视图的反弹效果起作用)

有什么建议或者问题出在哪里?

【问题讨论】:

“它显示在 View Container 的边界下方”:如果我理解正确,您的“View Container 没有扩大它的高度”?下一个问题:因此滚动视图不会增加/计算正确的内容大小? 它看起来更像是“ViewContainer”不会计算正确的内容大小另外,当 TopView 和 MiddleView 的内容高度较小时,所有视图下方都有“空白”空间 【参考方案1】:

关于布局功能,用Frame比较清楚,我根据你的描述写了一个样例:

using System;
using UIKit;
using CoreGraphics;

namespace LayoutSample

    public class MainViewController : UIViewController
    
        private MainView mainView;

        public override void LoadView()
        
            mainView = new MainView();
            this.View = mainView;
        

        public override void ViewDidLoad()
        
            //If you don't know what is this code meaning, try to comment it, then you will get what it is.
            this.AutomaticallyAdjustsScrollViewInsets = false;

            UIBarButtonItem left0 = new UIBarButtonItem("-Frame", UIBarButtonItemStyle.Done, delegate
            
                mainView.DecreaseScrollViewFrame();
            );

            UIBarButtonItem left1 = new UIBarButtonItem("-CS", UIBarButtonItemStyle.Done, delegate
            
                mainView.DecreaseScrollViewContentSize();
            );

            UIBarButtonItem right0 = new UIBarButtonItem("+Frame", UIBarButtonItemStyle.Done, delegate
            
                mainView.IncreaseScrollViewFrame();
            );

            UIBarButtonItem right1 = new UIBarButtonItem("+CS", UIBarButtonItemStyle.Done, delegate
            
                mainView.IncreaseScrollViewContentSize();
            );

            this.NavigationItem.SetLeftBarButtonItems(new UIBarButtonItem[]  left0,left1 , true);

            this.NavigationItem.SetRightBarButtonItems(new UIBarButtonItem[]  right0, right1 , true);

        
    

    class MainView : UIView
    
        private UIScrollView scrollView;
        private UIView containerView;
        private UIView topView;
        private UIView midView;
        private UIView bottomView;

        public MainView()
        
            scrollView = new UIScrollView();
            scrollView.BackgroundColor = UIColor.Red;
            nfloat navigationBarHeight = 64;
            scrollView.Frame = new CGRect(0, navigationBarHeight, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height - 100 - navigationBarHeight);
            scrollView.ContentSize = scrollView.Frame.Size;
            this.AddSubview(scrollView);

            containerView = new UIView();
            containerView.BackgroundColor = UIColor.Green;
            scrollView.AddSubview(containerView);

            topView = new UIView();
            topView.BackgroundColor = UIColor.Blue;
            containerView.AddSubview(topView);

            midView = new UIView();
            midView.BackgroundColor = UIColor.Purple;
            containerView.AddSubview(midView);

            bottomView = new UIView();
            bottomView.BackgroundColor = UIColor.Yellow;
            containerView.AddSubview(bottomView);
        

        //It will also be invoked when your view's Frame is changed, and of cause you can invoke it whenever you want
        public override void LayoutSubviews()
        
            Console.WriteLine("LayoutSubviews");

            nfloat padding = 10;

            CGRect containerFrame = new CGRect(new CGPoint(0,0),scrollView.ContentSize);
            containerFrame.X += padding;
            containerFrame.Y += padding;
            containerFrame.Width -= 2 * padding;
            containerFrame.Height -= 2 * padding;
            containerView.Frame = containerFrame;

            nfloat bottomHeight = 100;
            nfloat topHeight = 0.3f * containerView.Frame.Height;
            nfloat midHeight = containerView.Frame.Height - topHeight - bottomHeight - 4 * padding;

            nfloat containerSubviewWidth = containerView.Frame.Width - 2 * padding;
            topView.Frame = new CGRect(padding, padding, containerSubviewWidth, topHeight);
            midView.Frame = new CGRect(padding, padding + topView.Frame.Y + topView.Frame.Height, containerSubviewWidth, midHeight);
            bottomView.Frame = new CGRect(padding, padding + midView.Frame.Y + midView.Frame.Height, containerSubviewWidth, bottomHeight);
        

        public void IncreaseScrollViewContentSize()
        
            CGSize tmpSize = scrollView.ContentSize;
            tmpSize.Height += 100;
            scrollView.ContentSize = tmpSize;
            LayoutSubviews();
        

        public void DecreaseScrollViewContentSize()
        
            CGSize tmpSize = scrollView.ContentSize;
            tmpSize.Height -= 100;
            scrollView.ContentSize = tmpSize;
            LayoutSubviews();
        

        public void IncreaseScrollViewFrame()
        
            CGRect tmpRect = scrollView.Frame;
            tmpRect.Height += 10;
            scrollView.ContentSize = new CGSize(tmpRect.Width, tmpRect.Height);
            scrollView.Frame = tmpRect;
        

        public void DecreaseScrollViewFrame()
        
            CGRect tmpRect = scrollView.Frame;
            tmpRect.Height -= 10;
            scrollView.ContentSize = new CGSize(tmpRect.Width, tmpRect.Height);
            scrollView.Frame = tmpRect;
        
    

您可以更改参数以获得您想要的,这是我的GitHub中的完整解决方案:

lwnwowone/LayoutSample

如果需要,请查看。希望对你有帮助。

【讨论】:

感谢您提供的代码,但恐怕这不是我想要的。我的意思是,我确实使用自动布局。它应该解决任何约束更改,不是吗?我相信有更简单和优雅的解决方案,不涉及任何代码——我会说纯粹的“xCode 设计器约束解决方案”。但无论如何,谢谢你的工作! 是的,肯定有办法只用平面设计师来完成,但是当你遇到问题时更难讨论,因为除非你能分享整个解决方案,否则很难解释.如果你有一些合作者并且你想使用 Git/SVN 来管理你的项目,你会遇到很多合并问题。所以我建议你试试我的代码,这很容易。如果您仍然想使用设计器,您应该在某个地方分享您的解决方案,然后我或其他人可以帮助您。【参考方案2】:

已解决

以下方法成功了: 我已将 ScrollView 放在 View 中,所以现在层次结构看起来像这样(见图)

我唯一需要做的就是弄清楚如何正确处理在从 MiddleView 和 TopView 隐藏一些视图后剩余的额外空间(由于某种原因,将这些视图高度约束常量值设置为 0 是不够的......)。但这完全超出了我的问题范围:)

编辑

对于那些想知道如何解决我上面描述的额外空间问题的人,这里是帮助我解决问题的链接 - solution

【讨论】:

以上是关于如何使用 AutoLayout (iOS/Xamarin.iOS) 使 ScrollView 适合其内容?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用水平滚动以编程方式执行 AutoLayout?

如何使用 AutoLayout 使两个视图居中

如何使用 AutoLayout 均匀放置四个按钮? [复制]

如何使用 Autolayout 调整 UITableView 的大小?

如何防止 UIImageView 使用 Autolayout 调整大小

如何优雅的代码编写 AutoLayout