Search code examples
swiftautolayoutuikit

Is there a short way to assign all the anchors of a view equals to another view's all anchors


let's say I have a container view, which has an imageView and blurEffectView as its subView. In short, I apply a blurEffect on this image inside the container view.

I used anchors to configure the auto-layout programmatically without IB. And the anchors of imageView and blurredEffectView are completely the same as their container view.

I'm wondering is there a simple/quick way to do things like aView.allAnchors.equals(bView's allAnchors)? Then we could save a lot of repeating code.

- container
  - imageView
  - blurEffectView  
    let container: UIView = {
        let aView = UIView()
        aView.translatesAutoresizingMaskIntoConstraints = false
        return aView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        navigationController?.navigationBar.prefersLargeTitles = true
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        configureLayout()
    }
    
    func configureLayout() {
        
        let imageView = UIImageView(image: UIImage(named: "Wang Fei"))
//        imageView.frame = container.bounds
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        container.addSubview(imageView)

        let blurEffect = UIBlurEffect(style: .dark)
        let blurredEffectView = UIVisualEffectView(effect: blurEffect)
        blurredEffectView.translatesAutoresizingMaskIntoConstraints = false
//        blurredEffectView.frame = imageView.bounds
        container.addSubview(blurredEffectView)
        
        view.addSubview(container)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            container.topAnchor.constraint(equalTo: view.topAnchor),
            container.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            container.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            container.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.42),
            
            imageView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
            imageView.trailingAnchor.constraint(equalTo: container.trailingAnchor),
            imageView.topAnchor.constraint(equalTo: container.topAnchor),
            imageView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
            
            blurredEffectView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
            blurredEffectView.trailingAnchor.constraint(equalTo: container.trailingAnchor),
            blurredEffectView.topAnchor.constraint(equalTo: container.topAnchor),
            blurredEffectView.bottomAnchor.constraint(equalTo: container.bottomAnchor)
        ])
    }

Solution

  • You can use a frame instead of a constraint. Also, in code setting constraint and view inside the viewDidLayoutSubviewsit's not a good way. Also, use lazy.

    Here is the possible solution.

    class TestViewController: UIViewController {
        private lazy var container: UIView = {
            let aView = UIView()
            aView.translatesAutoresizingMaskIntoConstraints = false
            return aView
        }()
    
        
        private lazy var imageView: UIImageView = {
            let imageView = UIImageView(image: UIImage(named: "Red"))
            imageView.translatesAutoresizingMaskIntoConstraints = true
            imageView.contentMode = .scaleAspectFit
            return imageView
        }()
        
        private lazy var blurredEffectView: UIVisualEffectView = {
            let blurEffect = UIBlurEffect(style: .dark)
            let blurredEffectView = UIVisualEffectView(effect: blurEffect)
            blurredEffectView.translatesAutoresizingMaskIntoConstraints = false
            return blurredEffectView
        }()
        
        
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .white
            navigationController?.navigationBar.prefersLargeTitles = true
            setViews()
        }
    
        
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            self.imageView.frame = container.bounds
            self.blurredEffectView.frame = container.bounds
        }
        
        private func setViews() {
            view.addSubview(container)
            
            let g = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                container.topAnchor.constraint(equalTo: view.topAnchor),
                container.leadingAnchor.constraint(equalTo: g.leadingAnchor),
                container.trailingAnchor.constraint(equalTo: g.trailingAnchor),
                container.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.42)])
            
            container.addSubview(imageView)
            container.addSubview(blurredEffectView)
        }
    }