以Swift编程方式添加全尺寸视图

3

我正在使用iMessage应用程序,并已编程添加了一个视图。但是,我似乎无法找到正确的约束条件,以使其始终具有正确的大小。例如,如果我离开扩展并返回,该视图会向下移动几百像素。我认为这与.isActive有关。我的目标是使视图自动调整大小,始终具有正确的大小或占用全部可用高度和宽度。

func createBrowser() {
    let controller = MSStickerBrowserViewController(stickerSize: .small)
    addChildViewController(controller)
    view.addSubview(controller.view)

    controller.view.translatesAutoresizingMaskIntoConstraints = false
    controller.stickerBrowserView.backgroundColor = UIColor.blue
    controller.stickerBrowserView.dataSource = self

    view.topAnchor.constraint(equalTo: controller.view.topAnchor).isActive = true
    view.bottomAnchor.constraint(equalTo: controller.view.bottomAnchor).isActive = true
    view.leftAnchor.constraint(equalTo: controller.view.leftAnchor).isActive = true
    view.rightAnchor.constraint(equalTo: controller.view.rightAnchor).isActive = true
    view.centerXAnchor.constraint(equalTo: controller.view.centerXAnchor).isActive = true
    view.centerYAnchor.constraint(equalTo: controller.view.centerYAnchor).isActive = true
}

截图: https://d17oy1vhnax1f7.cloudfront.net/items/1F2B0s3v0s1k3E2L0Z07/Screen%20Shot%202016-09-19%20at%2011.42.51%20AM.png


这段内容展示了一个图片截屏的链接。

这可能是一个愚蠢的问题/我可能没有正确阅读您的代码,但是您是否把约束条件搞反了?难道您不应该根据旧视图的约束条件设置新视图的约束条件吗?在我看来,您似乎是根据新子控制器的视图设置父控制器视图的约束条件。 - Marcus
@Sparky 你是指像这样吗?controller.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true。我试过了,但行为还是一样的。 - Paint Laurent
@Sparky?抱歉,我在iOS开发方面比较新。能帮个忙吗?谢谢! - Paint Laurent
2个回答

0
为了更好地解释,我编写了以下内容。这演示了两种修复子视图布局的方法。使用约束时,我更喜欢将约束创建为数组,并在一次激活它们,正如您将在createredSquareWithConstraints的代码中看到的那样。约束只是一个线性方程,将一个视图的特征与另一个视图的特征相关联。例如,在“伪代码”中,我的数组中的第一个约束可以写成:
“将子视图的前导边距设置为容器视图的前导边距的1倍加上常数0。”
(这就是为什么我之前感到困惑的原因,因为在我看来,您正在根据其子视图的特征设置包含视图的约束。)
虽然使用布局约束仍然完全有效,但我认为现在首选的方法是覆盖viewWillTransitionToSize()委托方法,该方法仅要求您指定给定包含视图大小的情况下,视图控制器的子视图的框架应该是什么。因此,我也包括了这种实现,创建了一个具有初始框架的黄色正方形,每当调用viewWillTransitionToSize时就会修改该框架。我个人发现这比使用布局约束要简单得多。
如果您尝试按下按钮并旋转屏幕,您会发现两种方法都可以实现同样的效果。[注意:我将一个正方形标记为受限制的,另一个标记为不受限制的,但实际上它们当然都是受限制的,只是以不同的方式。我想补充说明的是,这显然不是您在实践中应该采取的做法 - 您应该选择一种方法并坚持使用,否则您的代码将无处不在!]
希望这有所帮助!
import UIKit

class ViewController: UIViewController {

    var constrainedredSquare : UIView!
    var unconstrainedRedSquare : UIView!
    var methodOneButton : UIButton!
    var methodTwoButton : UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.view.backgroundColor = UIColor.blue

        func getButton(name: String) -> UIButton {
            let button : UIButton = UIButton()
            button.backgroundColor = UIColor.white
            button.layer.cornerRadius = 3
            button.clipsToBounds = true
            button.setTitle(name, for: UIControlState.normal)
            button.setTitleColor(UIColor.black, for: UIControlState.normal)
            return button
        }

        self.methodOneButton = getButton(name: "Red - Constraints")
        self.methodTwoButton = getButton(name: "Yellow - viewWillTransitionToSize")

        self.methodOneButton.addTarget(self, action: #selector(self.createRedSquareWithConstraints), for: .touchUpInside)
        self.methodTwoButton.addTarget(self, action: #selector(self.createYellowSquareWithoutConstraints), for: .touchUpInside)
        self.methodOneButton.frame = CGRect(origin: CGPoint(x: 200, y: 100), size: CGSize(width: 300, height: 300))
        self.methodTwoButton.frame = CGRect(origin: CGPoint(x: self.view.frame.width - 500, y: 100), size: CGSize(width: 300, height: 300))
        self.view.addSubview(self.methodOneButton)
        self.view.addSubview(self.methodTwoButton)

    }

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

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        if let _ = self.unconstrainedRedSquare {
            self.unconstrainedRedSquare.frame = CGRect(origin: CGPoint.zero, size: size)
        }
        self.methodOneButton.frame = CGRect(origin: CGPoint(x: 200, y: 100), size: CGSize(width: 300, height: 300))
        self.methodTwoButton.frame = CGRect(origin: CGPoint(x: size.width - 500, y: 100), size: CGSize(width: 300, height: 300))
    }


    func createYellowSquareWithoutConstraints() {
        if let _ = self.unconstrainedRedSquare {
            self.unconstrainedRedSquare.removeFromSuperview()
        }
        else
        {
            if let _ = constrainedredSquare {
                self.constrainedredSquare.removeFromSuperview()
            }
            self.unconstrainedRedSquare = UIView()
            self.unconstrainedRedSquare.backgroundColor = UIColor.yellow
            self.unconstrainedRedSquare.frame = CGRect(origin: CGPoint.zero, size: self.view.frame.size)
            self.view.addSubview(self.unconstrainedRedSquare)

            self.view.bringSubview(toFront: self.methodOneButton)
            self.view.bringSubview(toFront: self.methodTwoButton)
        }

    }

    func createRedSquareWithConstraints() {
        if let _ = self.constrainedredSquare {
            self.constrainedredSquare.removeFromSuperview()
        }
        else
        {
            if let _ = self.unconstrainedRedSquare {
                self.unconstrainedRedSquare.removeFromSuperview()
            }
            let redSquare : UIView = UIView()
            redSquare.backgroundColor = UIColor.red

            self.view.addSubview(redSquare)

            self.view.bringSubview(toFront: self.methodOneButton)
            self.view.bringSubview(toFront: self.methodTwoButton)

            let rsConstraints : [NSLayoutConstraint] = [NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.leading, multiplier: 1.0, constant: 0),
                                                 NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.trailing, multiplier: 1.0, constant: 0),
                                                 NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.top, multiplier: 1.0, constant: 0),
                                                 NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.bottom, multiplier: 1.0, constant: 0),
                                                 NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.width, multiplier: 1.0, constant: 0),
                                                 NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.height, multiplier: 1.0, constant: 0)]
            redSquare.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate(rsConstraints)
        }
    }
}

0
你可以使用我的扩展来处理 UIView。它允许在任何边缘添加额外的填充(仅当你需要时):
public extension UIView {
    typealias ConstraintsTupleStretched = (top:NSLayoutConstraint, bottom:NSLayoutConstraint, leading:NSLayoutConstraint, trailing:NSLayoutConstraint)
    func addSubviewStretched(subview:UIView?, insets: UIEdgeInsets = UIEdgeInsets() ) -> ConstraintsTupleStretched? {
        guard let subview = subview else {
            return nil
        }

        subview.translatesAutoresizingMaskIntoConstraints = false
        addSubview(subview)

        let constraintLeading = NSLayoutConstraint(item: subview,
                                                   attribute: .Left,
                                                   relatedBy: .Equal,
                                                   toItem: self,
                                                   attribute: .Left,
                                                   multiplier: 1,
                                                   constant: insets.left)
        addConstraint(constraintLeading)

        let constraintTrailing = NSLayoutConstraint(item: self,
                                                    attribute: .Right,
                                                    relatedBy: .Equal,
                                                    toItem: subview,
                                                    attribute: .Right,
                                                    multiplier: 1,
                                                    constant: insets.right)
        addConstraint(constraintTrailing)

        let constraintTop = NSLayoutConstraint(item: subview,
                                               attribute: .Top,
                                               relatedBy: .Equal,
                                               toItem: self,
                                               attribute: .Top,
                                               multiplier: 1,
                                               constant: insets.top)
        addConstraint(constraintTop)

        let constraintBottom = NSLayoutConstraint(item: self,
                                                  attribute: .Bottom,
                                                  relatedBy: .Equal,
                                                  toItem: subview,
                                                  attribute: .Bottom,
                                                  multiplier: 1,
                                                  constant: insets.bottom)
        addConstraint(constraintBottom)
        return (constraintTop, constraintBottom, constraintLeading, constraintTrailing)
    }

}

使用方法:

view.addSubviewStretched(tableView)

let BorderedBackgroundInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
view?.addSubviewStretched(calendar.view, insets: BorderedBackgroundInset)

不得不调整代码中的约束以满足最新版本的Swift,但是这非常完美,谢谢! - Paint Laurent
收到这条消息:“调用'addSubvieStretched(subview:insets:)'的结果未被使用。这是什么意思? - Paint Laurent
这里有一个更好的错误截图:https://www.dropbox.com/s/8gi67ulcjuldm4k/Screenshot%202016-10-05%2012.24.48.png?dl=0 和 https://www.dropbox.com/s/t9ks7d02coycicb/Screenshot%202016-10-05%2012.26.34.png?dl=0 - Paint Laurent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接