代码之家  ›  专栏  ›  技术社区  ›  Ben

StackView中的按钮约束(Swift编程)

  •  1
  • Ben  · 技术社区  · 6 年前

    我对以编程方式设置堆栈视图和按钮还不熟悉。我有一些奇怪的行为与我的约束我不能找出我做错了什么。感觉我错过了一些简单的东西。非常感谢您的帮助!

    enter image description here

    // View to put in the StackView
    class ProfileBottomTabBarView: UIView {
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            self.translatesAutoresizingMaskIntoConstraints = false
            self.backgroundColor = .blue
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
    }
    
    // Calculate the screen height
    public var screenHeight: CGFloat {
        return UIScreen.main.bounds.height
    }
    
    // StackView height set to a proporation of screen height
    let stackViewHeight = screenHeight * 0.07
    
    // Views to put in the StackView
    let profileIconView = ProfileBottomTabBarView()
    let actIconView = ActBottomTabBarView()
    let achieveIconView = AchieveBottomTabBarView()
    let growIconView = GrowBottomTabBarView()
    
    // Buttons to put in the Views
    let profileButton = UIButton(type: .system)
    let actButton = UIButton(type: .system)
    let achieveButton = UIButton(type: .system)
    let growButton = UIButton(type: .system)
    
    let profileButtonText = UIButton(type: .system)
    let actButtonText = UIButton(type: .system)
    let achieveButtonText = UIButton(type: .system)
    let growButtonText = UIButton(type: .system)
    
    // Stackview setup
    lazy var stackView: UIStackView = {
    
        let stackV = UIStackView(arrangedSubviews: [profileIconView, actIconView, achieveIconView, growIconView])
    
        stackV.translatesAutoresizingMaskIntoConstraints = false
        stackV.axis = .horizontal
        stackV.spacing = 20
        stackV.distribution = .fillEqually
    
        return stackV
    }()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
    view.backgroundColor = .black
    
        // Add StackView
        view.addSubview(stackView)
    
        stackView.bottomAnchor.constraint(equalTo: view.safeBottomAnchor).isActive = true
        stackView.leadingAnchor.constraint(equalTo: view.safeLeadingAnchor).isActive = true
        stackView.trailingAnchor.constraint(equalTo: view.safeTrailingAnchor).isActive = true
    
        // Set height of the bottom tab bar as a proportion of the screen height.
        stackView.heightAnchor.constraint(equalToConstant: stackViewHeight).isActive = true
    
        profileIconView.topAnchor.constraint(equalTo: stackView.topAnchor).isActive = true
        profileIconView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor).isActive = true
        profileIconView.heightAnchor.constraint(equalToConstant: stackViewHeight).isActive = true
    
    
        // Add Buttons to the View
        profileIconView.addSubview(profileButton)
        profileIconView.addSubview(profileButtonText)
    
        profileButton.translatesAutoresizingMaskIntoConstraints = false
        profileButtonText.translatesAutoresizingMaskIntoConstraints = false
    
    
        // Profile Button with Earth Image Setup
        profileButton.setImage(UIImage(named: "earthIcon"), for: .normal)
        profileButton.imageView?.contentMode = .scaleAspectFit
    
        profileButton.topAnchor.constraint(equalTo: profileIconView.topAnchor).isActive = true
        profileButton.bottomAnchor.constraint(equalTo: profileButtonText.topAnchor).isActive = true
        profileButton.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor).isActive = true
    
        //Set height of icon to a proportion of the stackview height
        let profileButtonHeight = stackViewHeight * 0.8
        profileButton.heightAnchor.constraint(equalTo: profileIconView.heightAnchor, constant: profileButtonHeight).isActive = true
    
        profileButton.widthAnchor.constraint(equalToConstant: profileButtonHeight).isActive = true
        profileButton.imageView?.widthAnchor.constraint(equalToConstant: profileButtonHeight)
        profileButton.imageView?.heightAnchor.constraint(equalToConstant: profileButtonHeight)
    
    
        // Profile Text Button Setup
    
        profileButtonText.setTitle("Profile", for: .normal)
        profileButtonText.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12)
        profileButtonText.setTitleColor(.white, for: .normal)
    
        profileButtonText.topAnchor.constraint(equalTo: profileButton.bottomAnchor).isActive = true
        profileButtonText.bottomAnchor.constraint(equalTo: profileIconView.bottomAnchor).isActive = true
        profileButtonText.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor).isActive = true
    
        //Set height of icon to a proportion of the stackview height
        let profileButtonTextHeight = stackViewHeight * 0.2
        profileButton.heightAnchor.constraint(equalTo: profileIconView.heightAnchor, constant: profileButtonTextHeight).isActive = true
        profileButtonText.widthAnchor.constraint(equalToConstant: 40).isActive = true
    
    }
    
    1 回复  |  直到 6 年前
        1
  •  4
  •   DonMag    6 年前

    您正在计算高度/宽度并将其用作常量,但这些值可能(几乎肯定会)根据视图生命周期而改变。

    最好只使用相关的约束。例如:

            // constrain profile image button top, centerX and width relative to the iconView
            profileButton.topAnchor.constraint(equalTo: profileIconView.topAnchor),
            profileButton.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor),
            profileButton.widthAnchor.constraint(equalTo: profileIconView.widthAnchor, multiplier: 1.0),
    
            // constrain profile text button bottom, centerX and width relative to the iconView
            profileButtonText.centerXAnchor.constraint(equalTo: profileIconView.centerXAnchor),
            profileButtonText.widthAnchor.constraint(equalTo: profileIconView.widthAnchor, multiplier: 1.0),
            profileButtonText.bottomAnchor.constraint(equalTo: profileIconView.bottomAnchor),
    
            // constrain bottom of image button to top of text button (with a padding of 4-pts, change to suit)
            profileButton.bottomAnchor.constraint(equalTo: profileButtonText.topAnchor, constant: -4.0),
    
            // constrain height of text button to 20% of height of iconView
            profileButtonText.heightAnchor.constraint(equalTo: profileIconView.heightAnchor, multiplier: 0.2),
    

    BottomTabBarView 处理添加和约束按钮的:

    class BottomTabBarView: UIView {
    
        var theImageButton: UIButton = {
            let v = UIButton()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.imageView?.contentMode = .scaleAspectFit
            return v
        }()
    
        var theTextButton: UIButton = {
            let v = UIButton()
            v.translatesAutoresizingMaskIntoConstraints = false
            v.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12)
            v.setTitleColor(.white, for: .normal)
            return v
        }()
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            commonInit()
        }
    
        convenience init(withImageName imageName: String, labelText: String, bkgColor: UIColor) {
    
            self.init()
            self.commonInit()
            theImageButton.setImage(UIImage(named: imageName), for: .normal)
            theTextButton.setTitle(labelText, for: .normal)
            backgroundColor = bkgColor
    
        }
    
        func commonInit() -> Void {
            self.translatesAutoresizingMaskIntoConstraints = false
    
            addSubview(theImageButton)
            addSubview(theTextButton)
    
            NSLayoutConstraint.activate([
    
                // constrain profile image button top, centerX and width of the iconView
                theImageButton.topAnchor.constraint(equalTo: topAnchor),
                theImageButton.centerXAnchor.constraint(equalTo: centerXAnchor),
                theImageButton.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.0),
    
                // constrain profile text button bottom, centerX and width of the iconView
                theTextButton.centerXAnchor.constraint(equalTo: centerXAnchor),
                theTextButton.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 1.0),
                theTextButton.bottomAnchor.constraint(equalTo: bottomAnchor),
    
                // constrain bottom of image button to top of text button
                theImageButton.bottomAnchor.constraint(equalTo: theTextButton.topAnchor, constant: -4.0),
    
                // set text button height to 20% of view height (instead of using intrinsic height)
                theTextButton.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.2),
    
                ])
    
        }
    
    }
    

        profileIconView = BottomTabBarView(withImageName: "earthIcon", labelText: "Profile", bkgColor: .blue)
    

    class BenViewController: UIViewController {
    
        // Views to put in the StackView
        var profileIconView = BottomTabBarView()
        var actIconView = BottomTabBarView()
        var achieveIconView = BottomTabBarView()
        var growIconView = BottomTabBarView()
    
        // Stackview setup
        lazy var stackView: UIStackView = {
            let stackV = UIStackView(arrangedSubviews: [profileIconView, actIconView, achieveIconView, growIconView])
    
            stackV.translatesAutoresizingMaskIntoConstraints = false
            stackV.axis = .horizontal
            stackV.spacing = 20
            stackV.distribution = .fillEqually
    
            return stackV
        }()
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = .black
    
            profileIconView = BottomTabBarView(withImageName: "earthIcon", labelText: "Profile", bkgColor: .blue)
            actIconView = BottomTabBarView(withImageName: "actIcon", labelText: "Action", bkgColor: .brown)
            achieveIconView = BottomTabBarView(withImageName: "achieveIcon", labelText: "Achieve", bkgColor: .red)
            growIconView = BottomTabBarView(withImageName: "growIcon", labelText: "Grow", bkgColor: .purple)
    
            // Add StackView
            view.addSubview(stackView)
    
            NSLayoutConstraint.activate([
    
                // constrain stackView to bottom, leading and trailing (to safeArea)
                stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
                stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
    
                // Set height of the stackView (the bottom tab bar) as a proportion of the view height (7%).
                stackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.07),
    
                ])
    
        }
    }