以编程方式创建UIScrollView作为另一个UIView的子视图的必要步骤是什么?

时间:2015-12-29 04:59:41

标签: ios iphone swift uiview uiscrollview

TL; DR - >创建扩展UIScrollView的类,实例化该类,然后使用NSLayoutConstraints为我的UI添加它作为现有UIView的子视图的必要步骤是什么?

我需要在现有的UIViewController子视图中添加UIScrollView(不是self.view - self.view的子级)。我也没有使用IB,因为我想了解我的代码。我设法布置了每个UI组件,我可以看到我的视图层次结构已在调试器中正确组装。

不幸的是,我的UIScrollView不会滚动,因为某些原因我的子视图都没有直观显示(请注意,我的滚动视图的直接子节点也是滚动视图,因此我的问题可能是我对UIScrollView类的理解)。 / p>

enter image description here

上图显示了我的UI的一般结构,浅灰色区域是我的UIScrollView。我有一个扩展UIScrollView和UIScrollDelegate的类(如果需要后一个父类,则不是100%)。该课程看起来像这样

import UIKit

class PlayWorkout: UIScrollView, UIScrollViewDelegate{

var workoutInstructionTiles : [WorkoutInstruction] = [WorkoutInstruction]();

var heightsTotal : Int = 0; //This variable will keep track of the running total for each of the workout tile subviews to help with positioning

init(workoutSubviews : [WorkoutInstruction]){

    super.init(frame : CGRect.zero);
    workoutInstructionTiles = workoutSubviews;
    appendTiles();

    self.translatesAutoresizingMaskIntoConstraints = false;

}


func appendTiles(){

    print("appending tiles \(workoutInstructionTiles.count)");
    for(var i = 0; i < workoutInstructionTiles.count; i++){

        let setCount = workoutInstructionTiles[i].getNumSets();

        workoutInstructionTiles[i].layer.cornerRadius = 5;
        workoutInstructionTiles[i].backgroundColor    = UIColor.whiteColor();
        workoutInstructionTiles[i].translatesAutoresizingMaskIntoConstraints = false;
        changeContentSize(workoutInstructionTiles[i]);
        self.addSubview(workoutInstructionTiles[i]);

        //Formula for position relative to top of the ScrollView will be 10 (margin) + 20 (label space) + setCount * 20 (content) + heightsTotal
        let verticalConstraint = NSLayoutConstraint(item: workoutInstructionTiles[i], attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: CGFloat(30  + heightsTotal));

        let leftConstraint = NSLayoutConstraint(item: workoutInstructionTiles[i], attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Trailing, multiplier: 1.0, constant: 10);

        let rightConstraint = NSLayoutConstraint(item: workoutInstructionTiles[i], attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 10);

        let heightConstraint = NSLayoutConstraint(item: workoutInstructionTiles[i], attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: CGFloat(setCount * 20 + 20));

        self.addConstraints([verticalConstraint, leftConstraint, rightConstraint, heightConstraint]);
        heightsTotal += setCount * 20;
    }

}



func setViewConstraints(superView : UIView) -> Void{

    let verticalConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: superView, attribute: NSLayoutAttribute.CenterY, multiplier: 1.0, constant:30);

    let horizontalConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: superView, attribute: NSLayoutAttribute.CenterXWithinMargins, multiplier: 1.0, constant: 0);

    let heightConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: superView, attribute: NSLayoutAttribute.Height, multiplier: 1.0, constant: -60);

    let widthConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: superView, attribute: NSLayoutAttribute.Width, multiplier: 1.0, constant: 0);

    superView.addConstraints([verticalConstraint, horizontalConstraint, heightConstraint, widthConstraint]);

}

func changeContentSize(aView : UIView){

    var contentRect : CGRect = CGRect.zero;
    for view in aView.subviews {
        contentRect = CGRectUnion(contentRect, view.frame);
    }
    self.contentSize = contentRect.size;
}



required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

然后,当单击一个按钮开始锻炼时,我会实现该类。从我迄今为止能够确定的内容来看,我需要为UIScrollView调用/设置的唯一方法是

scrollView.contentSize = CGSize(width: aWidth, height: aHeight)
scrollView.translateAutoResizingMaskIntoConstraints = false

所以,这是我的类实例化 - 这是在UIViewController内的UIGestureRecognizer事件处理程序内部,它也扩展了UIScrollViewDelegate:

workoutConfig = PlayWorkout(workoutSubviews : workoutInstructions);
workoutConfig.delegate = self;
workoutConfig.changeContentSize(workoutConfig);
workoutConfig.translatesAutoresizingMaskIntoConstraints = false;
self.contentView.addSubview(workoutConfig);
workoutConfig.setViewConstraints(self.contentView);

我还使用了一个名为changeContentSize()的方法,该方法改编自发布到SO的Objective-C方法,如下所示:

func changeContentSize(aView : UIView){

    var contentRect : CGRect = CGRect.zero;
    for view in aView.subviews {
        contentRect = CGRectUnion(contentRect, view.frame);
    }
    self.contentSize = contentRect.size;
}

我知道很多阅读,但我想要彻底。我感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:0)

好的,所以经过3天疯狂的研究,并且为了实现这一目标而走下各种无意义的道路,我终于得到了它,而且实际上并不那么难(苹果的记录非常糟糕)。我将尝试分享我发现的内容 - 这个链接最终帮助我理解了如何做到这一点,所以我觉得有必要给予应有的信用:

http://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/#comment-541731

好的,这是使用自动布局创建可滚动视图的一步一步。

1 - UIScrollView只能有1个子视图,通常应该是UIView     保存所有可滚动内容。确保创建一个UIView,添加要滚动到该UIView的任何内容,然后将该UIView添加为UIScrollView的子视图

2 - 使用您想要的任何约束将滚动视图固定到其超级视图,只需确保设置顶部,前导,尾部和底部。这是我的代码的样子(在我的例子中,self是一个扩展UIScrollView的类):

func setViewConstraints(superView : UIView) -> Void{

    let verticalConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: superView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant:60);

    let leftConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: superView, attribute: NSLayoutAttribute.Trailing, multiplier: 1.0, constant: 0);

    let rightConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: superView, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 0);

    let bottomConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.Bottom, relatedBy: .Equal, toItem: superView, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: 0);


    superView.addConstraints([verticalConstraint, leftConstraint, bottomConstraint,rightConstraint]);

}

3 - 将UIView在步骤1中提到的子项固定到确保设置的滚动视图 - &gt;顶部,前导,尾随和底部。除非UIView设计为小于滚动视图的尺寸,否则通常应该完全固定。完成此步骤以确保设备知道放置UIView的位置。我的代码看起来像这样(再次,self指的是扩展UIScrollView的类)

    let pinTop = NSLayoutConstraint(item: subScrollView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant:0);

    let pinBottom = NSLayoutConstraint(item: subScrollView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: 0);

    let pinLeft = NSLayoutConstraint(item: subScrollView, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 0);

    let pinRight = NSLayoutConstraint(item: subScrollView, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Trailing, multiplier: 1.0, constant: 0);


    self.addConstraints([pinTop, pinBottom, pinLeft, pinRight]);

4 - 为了使滚动视图能够理解视图的内容大小,您必须根据滚动视图的概念设置高度和视野的宽度,或者进行滚动视图的计算。不要担心相对于滚动视图superview设置UIView的其他维度,只需要高度和宽度来使cocoa api推断内容大小。我的代码看起来像这样(在这种情况下,self.viewController.contentView引用了滚动视图的超级视图):

    let widthConstraint = NSLayoutConstraint(item: subScrollView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: self.viewController.contentView, attribute: NSLayoutAttribute.Width, multiplier: 1.0, constant: 0);


    let heightConstraint = NSLayoutConstraint(item: subScrollView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: CGFloat(heightsTotal + (self.workoutInstructionTiles.count * 10)));


    self.viewController.contentView.addConstraints([heightConstraint, widthConstraint]);

如果正确遵循了这些步骤,则结果应该是可滚动的视图。现在我得到这个,如果我可以帮助任何人使用他们的代码,只需发表评论。