【问题标题】:Is there a short way to assign all the anchors of a view equals to another view's all anchors有没有一种捷径可以将一个视图的所有锚点分配给另一个视图的所有锚点
【发布时间】:2021-06-26 05:45:49
【问题描述】:

假设我有一个容器视图,它有一个 imageView 和 blurEffectView 作为它的子视图。简而言之,我在容器视图内的这个图像上应用了 blurEffect。

我在没有 IB 的情况下使用锚点以编程方式配置自动布局。而imageViewblurredEffectView的anchors和它们的容器视图完全一样。

我想知道是否有一种简单/快速的方法来执行aView.allAnchors.equals(bView's allAnchors) 之类的操作?这样我们就可以省去很多重复的代码了。

- 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)
        ])
    }

【问题讨论】:

  • 你可以使用框架代替约束。
  • 谢谢,你能告诉我一个关于如何用框架实现它的小sn-p吗?

标签: swift autolayout uikit


【解决方案1】:

没有内置快捷方式。所以大多数人都会写一个。或者他们采用提供此类快捷方式的现有框架; SnapKit 是一个受欢迎的选择。

【讨论】:

  • 所以没有本地方法可以做到这一点。但是,很高兴知道自动布局存在依赖性。我想看看它的代码,也许我可以自己带一些方便的扩展。
【解决方案2】:

您可以像这样将重复代码包装在方便的extension 中 -

import UIKit

extension UIView {
    func setUpEdgeToEdge(in container: UIView, insets: UIEdgeInsets = .zero) {
        NSLayoutConstraint.activate([
            self.topAnchor.constraint(equalTo: container.topAnchor, constant: insets.top),
            self.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: insets.left),
            self.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: insets.bottom),
            self.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -insets.right),
        ])
    }
}

现在你可以这样称呼它-

imageView.setUpEdgeToEdge(in: container)

// OR

imageView.setUpEdgeToEdge(in: container, insets: UIEdgeInsets(top: 10, left: 16, bottom: 10, right: 16))

【讨论】:

  • 这也是我觉得动态填充支持的好方法。
【解决方案3】:

您可以使用框架代替约束。此外,在viewDidLayoutSubviews 内的代码设置约束和视图中,这不是一个好方法。另外,请使用惰性。

这是可能的解决方案。

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)
    }
}

【讨论】:

  • 感谢frame 示例。我在我身边尝试了一个小实验。除此之外,我在容器关闭中使用let aView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.42)),以完全删除代码中的anchor 内容。虽然现在代码更整洁了,但不知道这是不是更好的方法。
  • 是的,布局代码应该在viewDidLoad中,只有边界变化会放在viewDidLayoutSubviews中。但是我不同意那些懒惰的东西,在那些UI元素上使用lazy或者不使用,它们只会被调用一次,在viewDidLoad之前或之后。所以这里用lazy是没有意义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-10
  • 2015-03-16
  • 2014-03-25
  • 1970-01-01
  • 2010-11-28
  • 1970-01-01
相关资源
最近更新 更多