How to Package Code Auto Layout tool?

繼上一篇 如何使用 Code Auto Layout ,我們發現 Code Auto Layout 的程式碼太長,太多元件會造成難以閱讀,所以我們今天打算來封裝 Code Auto Layout 工具。

思考與實作

// 加入 Subview
addSubview(infoTopStackView)

// 設置 layout
        infoTopStackView.translatesAutoresizingMaskIntoConstraints = false

// infoTopStackView topAnchor,對齊 cell topAnchor,並啟動約束
        infoTopStackView.topAnchor.constraint(equalTo: topAnchor).isActive = true

// infoTopStackView leadingAnchor,對齊 cell leadingAnchor,並啟動約束
        infoTopStackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true

// infoTopStackView bottomAnchor,對齊 cell bottomAnchor,並啟動約束
        infoTopStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

// infoTopStackView trailingAnchor,對齊 cell trailingAnchor,並啟動約束
        infoTopStackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true

我們先觀察一下,基本會用到的屬性有:

  1. topAnchor
  2. leadingAnchor
  3. bottomAnchor
  4. trailingAnchor
  5. widthAnchor
  6. heightAnchor
  7. 每次都要關閉的 translatesAutoresizingMaskIntoConstraints
  8. constant 的邊界值

我們需要 layout 的對象,基本上都屬於 View,所以我們打算在 View 上使用 Extension

讓我們先建立 extension UIView

extension UIView {

}

接著我們建立一個 func 並提供以上方法的參數接口

/**
     for view constraint
     
	- Parameter top: 上邊界約束
	- Parameter leading: 左邊屆約束
	- Parameter bottom: 下邊界約束
	- Parameter trailing: 右邊界約束
	- Parameter padding: constant with UIEdgeInsets
	- Parameter size: widthAnchor, heightAnchor with CGSize
*/
func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {

    }

接著我們開始接入 constraint

/**
     for view constraint
     
     - Parameter top: 上邊界約束
     - Parameter leading: 左邊屆約束
     - Parameter bottom: 下邊界約束
     - Parameter trailing: 右邊界約束
     - Parameter padding: constant with UIEdgeInsets
     - Parameter size: widthAnchor, heightAnchor with CGSize
     */
    func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {

		// 關閉 translatesAutoresizingMaskIntoConstraints
        translatesAutoresizingMaskIntoConstraints = false
        
		// 如果有,開啟約束
        if let top = top {
            topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
        }
        
        if let leading = leading {
            leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
        }
        
        if let bottom = bottom {
            bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
        }
        
        if let trailing = trailing {
            trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
        }
        
		// 如果不=0 開啟約束
        if size.width != 0 {
            widthAnchor.constraint(equalToConstant: size.width).isActive = true
        }
        
		// 如果不=0 開啟約束
        if size.height != 0 {
            heightAnchor.constraint(equalToConstant: size.height).isActive = true
        }
    }

因為我們常常會用到填滿視窗,我們可以在封裝一個方法

func fillSuperview(padding: UIEdgeInsets = .zero) {
        anchor(top: superview?.topAnchor, leading: superview?.leadingAnchor, bottom: superview?.bottomAnchor, trailing: superview?.trailingAnchor, padding: padding)
    }

最後我們的 extension 會像

extension UIView {
    
    func fillSuperview(padding: UIEdgeInsets = .zero) {
        anchor(top: superview?.topAnchor, leading: superview?.leadingAnchor, bottom: superview?.bottomAnchor, trailing: superview?.trailingAnchor, padding: padding)
    }
    
    /**
     for view constraint
     
     - Parameter top: 上邊界約束
     - Parameter leading: 左邊屆約束
     - Parameter bottom: 下邊界約束
     - Parameter trailing: 右邊界約束
     - Parameter padding: constant with UIEdgeInsets
     - Parameter size: widthAnchor, heightAnchor with CGSize
     */
    func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {
        translatesAutoresizingMaskIntoConstraints = false
        
        if let top = top {
            topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
        }
        
        if let leading = leading {
            leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
        }
        
        if let bottom = bottom {
            bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
        }
        
        if let trailing = trailing {
            trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
        }
        
        if size.width != 0 {
            widthAnchor.constraint(equalToConstant: size.width).isActive = true
        }
        
        if size.height != 0 {
            heightAnchor.constraint(equalToConstant: size.height).isActive = true
        }
    }
}

實際使用

回到我們的 SearchResultCellView(繼上一篇 如何使用 Code Auto Layout),替換我們封裝的方法。

舊方法如下:

// 加入 Subview
addSubview(infoTopStackView)

// 設置 layout
        infoTopStackView.translatesAutoresizingMaskIntoConstraints = false

// infoTopStackView topAnchor,對齊 cell topAnchor,並啟動約束
        infoTopStackView.topAnchor.constraint(equalTo: topAnchor).isActive = true

// infoTopStackView leadingAnchor,對齊 cell leadingAnchor,並啟動約束
        infoTopStackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true

// infoTopStackView bottomAnchor,對齊 cell bottomAnchor,並啟動約束
        infoTopStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

// infoTopStackView trailingAnchor,對齊 cell trailingAnchor,並啟動約束
        infoTopStackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true

新方法:

addSubview(overallStackView)
overallStackView.fillSuperview(padding: .init(top: 16, left: 16, bottom: 16, right: 16))

是不是簡單了許多呢!

如果你需要範例輔助您,請點此專案

感謝您的閱讀,祝你有個美好的 Coding

yasuoyuhao 2019/05/11
如果喜歡我的文章,可以按下喜歡或追隨讓我知道呦,更歡迎許多大神指點討論。感謝您的閱讀。
部落格:yasuoyuhao’s Area