ios - 如何使用 autoLayout 创建具有水平和垂直分页功能的健壮 ScrollView?

标签 ios swift uiscrollview autolayout

情况

所以我试图制作一个 UIScrollView,它基本上是一个菜单导航栏,用户可以通过在菜单项之间滑动来导航,其中页面垂直布局,子页面水平布局布局。样机:enter image description here

我这样做的方法是创建一个 UIScrollView,其框架大小为一个 UILabel,并且我设置了 isPagingEnabled为真。然后我尝试添加一个 UIStackView,每行表示一个页面,每行的内容是一个子页面。我将 scrollView.contentSize 设置为 UIStackView 的大小。问题是我所有标签的框架都是零,UIScrollView 不起作用。

:/

真的想避免获得帮助,因为我觉得我可以自己做这件事,但我已经为此花了两天时间,我已经失去了所有希望。

代码

这是我添加标签的代码。它调用 ScrollView 的 super View 的 init(因为 UIScrollView 在自定义 UIView 中,我称之为 crossNavigation View)。

private func addScrollViewLabels() {
    
    //Get Max Number of Items in a Single Row
    var maxRowCount = -1
    for item in items {
        if (item.contents.count > maxRowCount) {maxRowCount = item.contents.count}
    }
    
    self.rowsStackView.axis = .vertical
    self.rowsStackView.distribution = .fillEqually
    self.rowsStackView.alignment = .fill
    self.rowsStackView.translatesAutoresizingMaskIntoConstraints = false
    self.scrollView.addSubview(rowsStackView)
    
    for i in 0 ..< items.count {
        let row = items[i].contents
        let rowView = UIView()
        self.rowsStackView.addArrangedSubview(rowView)
        var rowLabels : [UILabel] = []
        //First Label
        rowLabels.append(UILabel())
        rowView.addSubview(rowLabels[0])
        
        NSLayoutConstraint(item: rowLabels[0], attribute: .leading, relatedBy: .equal, toItem: rowView, attribute: .leading, multiplier: 1.0, constant: 0.0).isActive = true
        NSLayoutConstraint(item: rowLabels[0], attribute: .top, relatedBy: .equal, toItem: rowView, attribute: .top, multiplier: 1.0, constant: 0.0).isActive = true
        NSLayoutConstraint(item: rowLabels[0], attribute: .bottom, relatedBy: .equal, toItem: rowView, attribute: .bottom, multiplier: 1.0, constant: 0.0).isActive = true
        NSLayoutConstraint(item: rowLabels[0], attribute: .width, relatedBy: .equal, toItem: containerView, attribute: .width, multiplier: 0.55, constant: 0.0).isActive = true
        //Middle Labels
        for j in 1 ..< row.count {
            rowLabels.append(UILabel())
            rowView.addSubview(rowLabels[j])
            
            //Stick it to it's left
            NSLayoutConstraint(item: rowLabels[j], attribute: .leading, relatedBy: .equal, toItem: rowLabels[j-1], attribute: .trailing, multiplier: 1.0, constant: 0.0).isActive = true
            //Stick top to rowView
            NSLayoutConstraint(item: rowLabels[j], attribute: .top, relatedBy: .equal, toItem: rowView, attribute: .top, multiplier: 1.0, constant: 0.0).isActive = true
            //Row Height is equal to rowView's Height
            NSLayoutConstraint(item: rowLabels[j], attribute: .height, relatedBy: .equal, toItem: rowView, attribute: .height, multiplier: 1.0, constant: 0.0).isActive = true
            //rowLabels[j].width = containerView.width * 0.55 (so other labels can peek around it)
            NSLayoutConstraint(item: rowLabels[j], attribute: .width, relatedBy: .equal, toItem: containerView, attribute: .width, multiplier: 0.55, constant: 0.0).isActive = true
        }
        
        //lastLabel.trailing = rowView.trailing
        NSLayoutConstraint(item: rowLabels[row.count-1], attribute: .trailing, relatedBy: .equal, toItem: rowView, attribute: .trailing, multiplier: 1.0, constant: 0.0).isActive = true
    }

    //Constraints for stack view:
    //rowsStackView.height = scrollView.height * items.count
    NSLayoutConstraint(item: rowsStackView, attribute: .height, relatedBy: .equal, toItem: scrollView, attribute: .height, multiplier: CGFloat(self.items.count), constant: 0.0).isActive = true
    //rowsStackView.height = scrollView.height * items.count
    NSLayoutConstraint(item: rowsStackView, attribute: .leading, relatedBy: .equal, toItem: containerView, attribute: .leading, multiplier: 1.0, constant: 0.0).isActive = true
    NSLayoutConstraint(item: rowsStackView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1.0, constant: 0.0).isActive = true
    NSLayoutConstraint(item: rowsStackView, attribute: .width, relatedBy: .equal, toItem: containerView, attribute: .width, multiplier: 1.0, constant: 0.0).isActive = true
    
    self.scrollView.contentSize = rowsStackView.frame.size
}

最佳答案

看看这个demo project我根据你的模型制作的。 它为您想要做的一切设置了框架。

检查 View 层次结构,您将了解在哪里配置布局以使其完全符合您的要求。

最后一步是调整分页,以便获得所需的快照行为。有很多方法可以做到这一点,但它有点复杂。

祝你好运!

ScreenShot

关于ios - 如何使用 autoLayout 创建具有水平和垂直分页功能的健壮 ScrollView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45558122/

相关文章:

swift - Swift 中 pthread_mutex_lock 的替代方案?

ios - UIPageControl 和 scrollViewDidScroll 有问题

ios - Swift:如何让 UIScrollView ClipsToBounds 仅水平工作。

ios - 接收我们在用户登录时存储的用户默认值(swift3 ...)

Swift 3 - 通过 Int 属性减少对象集合

ios - 如何在 viewDidLoad 之前初始化 UITableView?

ios - 将枚举案例的关联值提取到元组中

ios - 如何防止同时滚动多个 UIScrollView 对象?

ios - 无法通过 Swift For 循环进行迭代

ios - 在单词或字符边界处截断包含表情符号或 unicode 字符的字符串