iOS:使用ContainerView的动态内容的UIScrollView(一步一步) [英] iOS: UIScrollView with dynamic content using ContainerView (step by step)

查看:99
本文介绍了iOS:使用ContainerView的动态内容的UIScrollView(一步一步)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

即使这些问题存在多个问题和答案,我也无法使用静态和动态内容创建 UIScrollView (使用 ContainerView )并使大小正常工作。因此,我将提供一步一步的指导,直至我无法取得任何进展,有人可以提供解决方案。通过这种方式,我们将有一个可行的样本,可以一步一步地使其工作。



请注意:所有的输出为方便起见,将这些步骤上传到





第4步:运行应用程序:



运行应用程序并一直滚动到底部,包括反弹区域,这就是结果:





我们可以得出结论:




  • ContainerView 的位置是正确的(即 SecondLabel BottomLabel ),但 BottomLabel 不会使其约束低于 ContainerView

  • TableView 的高度显然是0.这也可以从未调用func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)。如果我们在 TableView 上设置高度约束,则会显示项目。

  • 的内容大小如果 ContainerView 的大小增加,ScrollView 不会增加。

  • 还需要显示<动态 TableView 中的strong>所有项目,只需滚动它们就好像它们只是 ScrollView中的静态数据一样/ code>。

  • 这件事真的很乱。



第5步:问题!




  • 我们如何制作 ScrollView 的内容正确包装所有内容,包括生活在 ContainerView 中的 TableView 中的动态数据?

  • 约束是否设置正确?

  • 我们应该在何处以及如何计算适当的高度/内容尺寸?

  • 所有这些都是必要的;是否有更简单的方法来实现这一目标?



步骤6:在@ agibson007的回答后修复解决方案:




  • 添加静态让CELL_HEIGHT = 44 这样:

      import UIKit 

    class TableViewCell:UITableViewCell {
    @IBOutlet weak var dataLabel:UILabel!
    静态让CELL_HEIGHT = 44
    }


  • 还原 TableView 的内在大小默认来自占位符


  • TableView 上设置例如150的高度约束。此值必须大于一个单元格的高度。

  • 将高度约束添加到 DynamicEmbeddedViewController 作为 IBOutlet

  • 添加代码以计算和​​设置 TableView 高度约束。最终课程:

      import UIKit 

    class DynamicEmbeddedViewController:UIViewController,UITableViewDataSource,UITableViewDelegate
    {
    @IBOutlet弱var tableView:UITableView!
    @IBOutlet弱var tableViewHeight:NSLayoutConstraint!

    让data = [First,Second,Third,Fourth,Fifth,Sixth,Last]

    覆盖func viewDidLoad(){
    super.viewDidLoad()
    tableView.register(UINib(nibName:TableViewCell,bundle:nil),forCellReuseIdentifier:TableViewCell)

    //调整约束大小
    let totalHeight = data.count * TableViewCell.CELL_HEIGHT
    tableViewHeight.constant = CGFloat(totalHeight)
    self.updateViewConstraints()
    //在一个真实的应用程序中委托回调可以更新滚动视图上的约束
    }

    func numberOfSections(在tableView:UITableView中) - > Int {
    return 1
    }

    func tableView(_ tableView:UITableView,numberOfRowsInSection section:Int) - > Int {
    return data.count
    }

    func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath) - > UITableViewCell {
    让cell = tableView.dequeueReusableCell(withIdentifier:TableViewCell,for:indexPath)为! TableViewCell
    cell.dataLabel.text = data [indexPath.row]
    return cell
    }

    }


  • ContainerView 的内在大小恢复为默认来自占位符


  • ContainerView上设置例如150的高度约束。该值将在代码中更新。

  • 将高度约束添加到 ContainerView 作为 IBOutlet FirstViewController

  • 添加 ContainerView FirstViewController 中的 IBOutlet

  • 创建对<$ c的引用$ c> DynamicEmbeddedViewController FirstViewController 中,以便可以参考高度计算。

  • 添加代码以计算和​​设置 ContainerView 高度约束。最终 FirstViewController 类:

      import UIKit 

    class FirstViewController:UIViewController {

    @IBOutlet weak var containerView:UIView!
    @IBOutlet weak var containerViewHeightConstraint:NSLayoutConstraint!
    var dynamicView:DynamicEmbeddedViewController?

    覆盖func viewDidLoad(){
    super.viewDidLoad()
    //加载视图后进行任何其他设置,通常是从nib。

    如果dynamicView!= nil {
    dynamicView?.tableView.reloadData()
    let size = dynamicView?.tableView.contentSize.height
    //作弊300,因为该控制器中的其他视图在150每个
    containerViewHeightConstraint.constant = size! + 300
    self.view.updateConstraintsIfNeeded()
    }
    }

    覆盖func didReceiveMemoryWarning(){
    super.didReceiveMemoryWarning()
    //处理可以重新创建的任何资源。
    }

    覆盖func prepare(对于segue:UIStoryboardSegue,发件人:Any?){
    if(segue.identifier ==ContainerViewSegue){
    dynamicView = segue.destination为? DynamicEmbeddedViewController
    }
    }

    }




最后一切都按预期工作!





请注意:所有步骤的输出都上传到



现在将UILabel拖到滚动视图上并快速查看警告。 ScrollView模糊可滚动内容(宽度和高度)。





现在添加顶部,底部,前导和尾部20人。



没有警告。





测试2)
删除UILabel并将UIView拖到滚动视图上并添加20的顶部,底部,前导和尾部。



警告!警告!警告!





问题是UIView没有能够自我调整大小并且滚动视图不知道其内容有多大,因此无法设置。






如果这样做的话SENSE == True
继续
ELSE
goBack



现在这里将变得更复杂,具体取决于我们走多远但是上面的概念管理整个过程。



调查你的项目和设置你做得很好,可以学习UIScrollview。



现在让我们回顾一下你的摘要,我会就某些事情发表评论。



从你的报价上面



从这里我们可以得出结论:
ContainerView的位置是正确的(即在SecondLabel和BottomLabel之间),但是BottomLabel不遵守它的约束低于ContainerView。



*** - >这里的摘要实际上是不正确的。转到标签上方的容器,并在界面构建器中选中要绑定的剪辑,然后重新运行项目,标签将位于底部,但不会显示绿色视图。为什么?它不知道应该有多大。当你在它加载之前运行它最好,它可以和uilabels清楚,所以当它超出它的界限时,看起来它是不正确的。



TableView的高度显然很明显这也可以看到,因为没有调用func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)。如果我们在TableView上设置了一个高度约束,项目就会出现。



*** - >这是最棘手的问题。您必须加载tableview并获取tableview内容大小并在代码中更新tableview上的高度约束,以使其更新为scrollview以调整持有控制器的容器的大小。



另一种选择是stackview,如果它所拥有的内容具有内在的内容大小,它可以确定它的高度和宽度。



但回到tableview。你需要在tableview上设置一个> = 40 //你的行高在动态视图上开始。在检查数据源之后,如果计数为0,则将约束更新为0并使用委托让scrollview知道更新动态视图控制器上的约束以不显示表。我希望这是有道理的。然后相反,如果计数是数据源中的10个项目更新,则动态视图控制台视图高度约束的约束为10 * 40,如此

  import UIKit 

class DynamicEmbeddedViewController:UIViewController,UITableViewDataSource,UITableViewDelegate
{
@IBOutlet weak var tableViewConstraint:NSLayoutConstraint!
@IBOutlet弱var tableView:UITableView!

让data = [First,Second,Third,Fourth,Fifth,Sixth,Last]

覆盖func viewDidLoad(){
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName:TableViewCell,bundle:nil) ),forCellReuseIdentifier:TableViewCell)

//调整约束大小
let count = data.count
let constant = count * 40
tableViewConstraint.constant = CGFloat (常量)
self.updateViewConstraints()
//在真实应用程序中委托回调可以更新滚动视图上的约束
}

在第一个控制器中它看起来像这样。

  import UIKit 

class FirstViewController:UIViewController {

@IBOutlet weak var containerViewHeightC onstraint:NSLayoutConstraint!
@IBOutlet weak var containerView:UIView!
@IBOutlet弱var scrollView:UIScrollView!
var dynamicView:DynamicEmbeddedViewController?
覆盖func viewDidLoad(){
super.viewDidLoad()
//加载视图后,通常从笔尖进行任何其他设置。

if dynamicView!= nil {
dynamicView?.tableView.reloadData()
// get size
let size = dynamicView?.tableView.contentSize.height
//在300上作弊,因为我看到你在那个控制器中设置其他视图,每个
containerViewHeightConstraint.constant = size! + 300
self.view.updateConstraintsIfNeeded()
}
}

覆盖func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
//处理可以重新创建的任何资源。
}

覆盖func prepare(对于segue:UIStoryboardSegue,发件人:Any?){
if(segue.identifier ==ContainerViewSegue){
dynamicView = segue.destination为? DynamicEmbeddedViewController
}
}

}

< a href =https://i.stack.imgur.com/RjogY.png =noreferrer>
您可以看到我们调整所有内容以适应。除此之外,你做对了。现在要生产有价值的代码。大多数情况下,您会知道将显示哪些内容,以便您可以控制它。另一种方法是对所有内容使用UITableView或UICollectionView,并根据内容加载不同的单元格。我希望这篇文章能够清除它。我相信我们可以继续添加它,但希望所涵盖的概念就足够了。如果这回答了你的问题,请表现出对这样做的热爱。如果你愿意,我也可以将它上传到GitHub,但你可能最好进入你开始的回购。


Even though there are multiple questions and answers to this questions here on SO I just cannot create a UIScrollView with both static and dynamic content (by using a ContainerView) and make the sizes work properly. I will therefore provide a step by step guide until the point where I cannot make any progress and someone can provide a solution. This way we will have a workable sample that can be followed step by step to make it work.

Please note: The output from all of the steps is uploaded to https://github.com/oysteinmyrmo/DynamicScrollablePage for convenience. The test Xcode project can be fetched from there and hacked on further.

Update: After @agibson007's answer, there are a few steps at the end to fix the original steps to a working solution. Errors are noted by stating ERROR, SEE FINAL STEPS.

Goal:

Have a long scrollable UIView page with various static UIViews and a ContainerView with dynamic content. For completeness' sake the dynamic content will consist of some static UIViews and a UITableView that will be expanded to its entire contents. The last element seems to be a reoccurring theme in the various questions I have stumbled upon lately.

Method:

  1. We will start with a new Xcode project (Xcode 8.2.1) and use Swift 3.0.2 as language.
  2. We will step by step create test UIViews, UIViewControllers and other required items.
  3. At some point we have a "template" that can be used to make the content expand dynamically by someone who are able.

Step 1: Project Creation

Open Xcode (8.2.1), start a new project.

  1. Select Tabbed Application. We will create the UIScrollView in the first tab.
  2. Set product name to DynamicScrollablePage.
  3. Select location and create the project.

Step 2: Initial Changes to the Project

The changes to the UI will be done in the first tab. The procedure is heavily influenced by this answer, but we will add a couple of more items and a ContainerView for our dynamic content.

  1. In Main.storyboard, First View (i.e. tab 1) delete the two labels.
  2. Click the UIViewController (named first). Go to its size inspector, change from Fixed to Freeform and change the height to 1500. This is only a visual change in the storyboard.
  3. Rename the remaining UIView as RootView.
  4. Add a UIScrollView inside RootView. Name it ScrollView. Constraints:
    • ScrollView[Top, Bottom, Leading, Trailing, Width] = RootView[Top, Bottom, Leading, Trailing, Width]. In my experience the width constraint must also be set to ensure covering the entire screen later on.
  5. Add a UIView inside ScrollView and name it ContentView. Constraints:
    • ContentView[Leading, Trailing, Top, Bottom, Width] = ScrollView[Leading, Trailing, Top, Bottom, Width]. The storyboard will now complain about scrolling height. It will not complain after the steps below.
  6. Add items to ContentView:
    • First add a UIView, name it RedView. Set RedView[Leading, Trailing, Top] = ContentView[Leading, Trailing, Top]. Set RedView[Height, Background Color] = [150, Red].
    • Add a UILabel below RedView, set its name/text to FirstLabel. Set FirstLabel[Leading, Trailing] = ContentView[Leading, Trailing]. Set FirstLabel[Top] = RedView[Bottom].
    • Add a UIView below FirstLabel, name it BlueView. Set BlueView[Leading, Trailing] = ContentView[Leading, Trailing]. Set BlueView[Top] = FirstLabel[Bottom]. Set BlueView[Height, Background Color] = [450, Blue].
    • Add a UILabel below BlueView, set its name/text to SecondLabel. Set SecondLabel[Leading, Trailing] = ContentView[Leading, Trailing]. Set SecondLabel[Top] = BlueView[Bottom].
    • Add a UIContainerView below SecondLabel, name it ContainerView. Set ContainerView[Leading, Trailing] = ContentView[Leading, Trailing]. Set ContainerView[Top] = SecondLabel[Bottom]. Set ContainerView[Intrinsic size] = [Placeholder] (see Size inspector for the ContainerView). Setting the intrinsic size to placeholder tells Xcode that the size of it is defined by its child views (as far as I understand). ERROR, SEE FINAL STEPS
    • Add a UILabel at the end, name it BottomLabel. Set BottomLabel[Leading, Trailing] = ContentView[Leading, Trailing]. Set BottomView[Top] = ContainerView[Bottom].
    • Finally, control + drag from ScrollView to BottomView and select Bottom Space to ScrollView. This will ensure that the ScrollView's height is correct.

Step 3: Create a ViewController with Dynamic Content

Now we will create the actual UIViewController and xib file that will be used to display the dynamic contents. We will create a UITableView inside the xib and thus we will also need a UITableViewCell with a simple label for simplicity.

  1. Create a Swift file, TableViewCell.swift with the contents:

    import UIKit
    
    class TableViewCell : UITableViewCell {
    }
    

  2. Create a xib/View file, named TableViewCell.xib. Do the following:

    • Remove the default UIView and replace it with a UITableViewCell.
    • Add a UILabel to that cell, name it DataLabel (it will also add a content view UIView).
    • Set UITableViewCell's custom class to TableViewCell.
    • Set the Table View Cell identifier to TableViewCellId.
    • In dual-view mode, ctrl+drag the label to the TableViewCell class. The result should be:

      import UIKit
      
      class TableViewCell : UITableViewCell {
          @IBOutlet weak var dataLabel: UILabel!
      }
      

  3. Create a file DynamicEmbeddedViewController.swift with the contents:

    import UIKit
    
    class DynamicEmbeddedViewController : UIViewController, UITableViewDataSource, UITableViewDelegate
    {
        @IBOutlet weak var tableView: UITableView!
        let data = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Last"]
    
        override func viewDidLoad() {
            super.viewDidLoad()
            tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")
        }
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return data.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
            cell.dataLabel.text = data[indexPath.row]
            return cell
        }
    }
    

  4. Create a xib/View file, named DynamicEmbeddedView.xib. Rename the main UIView to ContentView and add three items within the ContentView:

    • Add a UIView, name it GreenView. Set GreenView[Leading, Trailing, Top] = ContentView[Leading, Trailing, Top]. Set GreenView[Height] = [150].
    • Add a UITableView, name it TableView. Set TableView[Leading, Trailing] = ContentView[Leading, Trailing]. Set TableView[Top] = GreenView[Bottom]. Set Intrinsic size = Placeholder. I am not sure if this is the correct approach. ERROR, SEE FINAL STEPS
    • Add a UIView below TableView, name it PurpleView. Set PurpleView[Leading, Trailing] = ContentView[Leading, Trailing]. Set PurpleView[Top] = TableView[Bottom].
    • Note: At this point we might need some more constraints in the xib, but I am unsure what and how, if any.
    • Set the File's Owner's custom class to DynamicEmbeddedViewController.
    • Set the File's Owner's View outlet to ContainerView.
    • Set the TableView's dataSource and delegate to File's Owner.
    • Add the IBOutlet of the TableView to the DynamicEmbeddedViewController class.
  5. Connect the created xib and UIViewController in the Main.storyboard.

    • Set the Custom Class of the ContainerView's output View Controller to DynamicEmbeddedViewController.
    • Delete the existing View in the ContainerViews output View Controller. I am not sure if this is really needed.

Images of Current Situation:

Step 4: Running the app:

Running the app and scrolling all the way to the bottom, including bounce area, this is the result:

From this we can conclude:

  • The position of the ContainerView is correct (i.e. between SecondLabel and BottomLabel), but the BottomLabel does not adhere its constraint to be below the ContainerView.
  • The TableView's height is obviously 0. This can also be seen since func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) is not called. If we set a height constraint on the TableView, items will show up.
  • The content size of the ScrollView does not increase if the size of the ContainerView increases.
  • It is also desired to display all items in the dynamic TableView at all time and just scroll past them as if they were just static data in the ScrollView.
  • This thing is really messy.

Step 5: The questions!

  • How can we make the ScrollView's content properly wrap all the contents, including the dynamic data in the TableView living inside the ContainerView?
  • Are the constraints set up properly?
  • Where and how should we calculate the proper heights/content sizes?
  • Is all of this really necessary; are there easier ways to achieve this?

Step 6: Fixing the solution after @agibson007's answer:

  • Add static let CELL_HEIGHT = 44 like this:

    import UIKit
    
    class TableViewCell : UITableViewCell {
        @IBOutlet weak var dataLabel: UILabel!
        static let CELL_HEIGHT = 44
    }
    

  • Revert TableView's intrinsic size to Default from Placeholder.

  • Set height constraint of for example 150 on the TableView. This value must be greater than one cell's height.
  • Add the height constraint to the DynamicEmbeddedViewController as an IBOutlet.
  • Add code to calculate and set TableView height constraint. Final class:

    import UIKit
    
    class DynamicEmbeddedViewController : UIViewController, UITableViewDataSource, UITableViewDelegate
    {
        @IBOutlet weak var tableView: UITableView!
        @IBOutlet weak var tableViewHeight: NSLayoutConstraint!
    
        let data = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Last"]
    
        override func viewDidLoad() {
            super.viewDidLoad()
            tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")
    
            // Resize our constraint
            let totalHeight = data.count * TableViewCell.CELL_HEIGHT
            tableViewHeight.constant = CGFloat(totalHeight)
            self.updateViewConstraints()
            //in a real app a delegate call back would be good to update the constraint on the scrollview
        }
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return data.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
            cell.dataLabel.text = data[indexPath.row]
            return cell
        }
    
    }
    

  • Revert ContainerView's intrinsic size to Default from Placeholder.

  • Set height constraint of for example 150 on the ContainerView. This value will be updated in code.
  • Add the height constraint to the ContainerView as an IBOutlet in the FirstViewController.
  • Add the ContainerView as an IBOutlet in the FirstViewController.
  • Create reference to the DynamicEmbeddedViewController in FirstViewController so that it may be referenced for height calculation.
  • Add code to calculate and set ContainerView height constraint. Final FirstViewController class:

    import UIKit
    
    class FirstViewController: UIViewController {
    
        @IBOutlet weak var containerView: UIView!
        @IBOutlet weak var containerViewHeightConstraint: NSLayoutConstraint!
        var dynamicView: DynamicEmbeddedViewController?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
    
            if dynamicView != nil{
                dynamicView?.tableView.reloadData()
                let size = dynamicView?.tableView.contentSize.height
                //cheating on the 300 because the other views in that controller at 150 each
                containerViewHeightConstraint.constant = size! + 300
                self.view.updateConstraintsIfNeeded()
            }
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "ContainerViewSegue") {
                dynamicView = segue.destination as? DynamicEmbeddedViewController
            }
        }
    

    }

And finally everything works as expected!

Please note: The output from all of the steps is uploaded to https://github.com/oysteinmyrmo/DynamicScrollablePage for convenience. The test Xcode project can be fetched from there and hacked on further.

解决方案

I am sure this has been answered before but I cannot remember if it has been answered down to why people have so much trouble with a scrollview. It comes down to 2 things that you have to know about UIScrollView and Autolayout.

1) The scrollview needs to be able to calculate the width and height of the content that is inside. This helps with deciding if it actually needs to scroll.

2) Some views have a size based on the content inside. Example a UILabel has an "intrinsic" content size. That means if you drag it out onto the storyboard you do not need to set a height or width unless you are trying to constraint it someway. Other examples of views with intrinsic sizes would be a UIButton, UIImageView(if it has an image), UITextView(with scrolling disabled) and other controls that may have text or images in them.

So let's start really simple and drag a UIScrollView onto the storyboard and pin it to the superview. All is good no warnings.

Now drag a UILabel onto the scrollview and take a quick peak at the warnings. ScrollView ambiguous scrollable content(width and height).

Now add a top, bottom,leading, and trailing of 20 for all.

No warnings.

Test 2) Delete the UILabel and drag a UIView onto the scrollview and add top,bottom,leading,and trailing of say 20.

Warning! Warning! Warning!

The problem is that a UIView does not have the ability to size itself and the scrollview does not know how big its content will be so it cannot setup.


IF THIS MAKES SENSE == True continue ELSE goBack

Now here is where it will get more complex depending on how far we go but the concepts above govern the entire process.

Investigating your project and setup you did pretty well to be learning UIScrollview.

Now lets go over your summary and I will comment in line as to some things.

From your quote above

"From this we can conclude: The position of the ContainerView is correct (i.e. between SecondLabel and BottomLabel), but the BottomLabel does not adhere its constraint to be below the ContainerView."

***-> You summary here is actually incorrect. Go to the container above the label and checkmark clip to bounds in interface builder and re run the project and the label will be at the bottom but there will be no green view. Why? It does not know how big it is supposed to be. When you ran it before it loaded best it could and uilabels are clear so when it went outside its bounds it looked like it was not correct.

"The TableView's height is obviously 0. This can also be seen since func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) is not called. If we set a height constraint on the TableView, items will show up."

***-> This is the trickiest to deal with. You would have to load the tableview and get the tableview content size and update a height constraint on the tableview in code to get it to update for the scrollview to resize for the container that is holding the controller.

An alternative would be a stackview that can determine it's height and width if the content it holds has intrinsic content size.

But back to the tableview. You would need to set a >= 40 on the tableview//your row height to start on the dynamic view. After you check your datasource if the count is 0 you would update the constraint to 0 and use a delegate to let the scrollview know to update it's constraint on the dynamicviewcontroller to not show the table. I hope this makes sense. Then conversely if the count is say 10 items in the datasource update the constraint on both the dynamicviewcontroller tableview height constraint to 10 * 40 like so

import UIKit

    class DynamicEmbeddedViewController : UIViewController, UITableViewDataSource, UITableViewDelegate
    {
        @IBOutlet weak var tableViewConstraint: NSLayoutConstraint!
        @IBOutlet weak var tableView: UITableView!

        let data = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Last"]

        override func viewDidLoad() {
            super.viewDidLoad()
            tableView.delegate = self
            tableView.dataSource = self
            tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "TableViewCell")

            //resize our constraint
            let count = data.count
            let constant = count * 40
            tableViewConstraint.constant = CGFloat(constant)
            self.updateViewConstraints()
           //in a real app a delegate call back would be good to update the    constraint on the scrollview
        }

And in the first controller it would look like this.

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var containerViewHeightConstraint: NSLayoutConstraint!
    @IBOutlet weak var containerView: UIView!
    @IBOutlet weak var scrollView: UIScrollView!
    var dynamicView : DynamicEmbeddedViewController?
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        if dynamicView != nil{
            dynamicView?.tableView.reloadData()
            //get size 
            let size = dynamicView?.tableView.contentSize.height
            //cheating on the 300 because i see you set the other views in that controller at 150 each
            containerViewHeightConstraint.constant = size! + 300
            self.view.updateConstraintsIfNeeded()
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "ContainerViewSegue") {
            dynamicView = segue.destination as? DynamicEmbeddedViewController
        }
    }

}

You can see we resize everything to fit. Other than that you got it right. Now to production worthy code. Most times you would know what content would be shown so you can control it. Another way is to use UITableView or UICollectionView for all the content and have different cells that would load based on the content. I hope this post clears it up a bit. I am sure we could continue to add to it but hopefully the concepts covered will be enough. If this answers your questions please show some love for the time it takes to do this. I can also upload this to GitHub if you like but it might be best to go in the repo you started.

这篇关于iOS:使用ContainerView的动态内容的UIScrollView(一步一步)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆