반응형

Autolayout을 사용할때 Snapkit을 사용하지 않더라도 간단한 것들은 UIView Extension을 사용합니다.

// MARK: - Autolayout
extension UIView {
    /// Autolyout 배치 하는 모드
    enum AutoLayoutMode {
        /// 전체 화면
        case full
        /// center 위치
        case center
        /// top 위치
        case top
        /// bottom 위치
        case bottom
        /// leading 위치
        case leading
        /// leading 위치
        case trailing
    }
    
    /// Autolayout으로 하위 뷰 추가하기
    ///
    /// - Parameters:
    ///   - childView: 하위 뷰
    ///   - width: 하위 뷰의 넓이 (default = 0)
    ///   - height: 하위 뷰의 높이 (default = 0)
    ///   - offset: 부모와 하위 뷰간의 오프셋 (default = 0)
    ///   - isSafeArea: Safe Area 사용 기준 (default = false)
    ///   - mode: Autolayout 모드
    func addSubview(_ childView: UIView, width: CGFloat = 0, height: CGFloat = 0, offset: CGFloat = 0, isSafeArea: Bool = false, mode: AutoLayoutMode) {
        switch mode {
        case .full:
            addSubviewFull(childView, isSafeArea: isSafeArea)
        case .center:
            addSubviewCenter(childView, width: width, height: height)
        case .top:
            addSubviewTop(childView, height: height, offset: offset, isSafeArea: isSafeArea)
        case .bottom:
            addSubviewBottom(childView, height: height, offset: offset, isSafeArea: isSafeArea)
        case .leading:
            addSubviewLeading(childView, width: width, offset: offset, isSafeArea: isSafeArea)
        case .trailing:
            addSubviewTrailing(childView, width: width, offset: offset, isSafeArea: isSafeArea)
        }
    }
    
    /// 부모 뷰로 가득채우기
    ///
    /// - Parameters:
    ///   - childView: 하위 뷰
    ///   - isSafeArea: Safe Area 사용 기준 (default = false)
    func addSubviewFull(_ childView: UIView, isSafeArea: Bool = false) {
        addSubview(childView)
        childView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            childView.topAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.topAnchor : topAnchor),
            childView.leadingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.leadingAnchor : leadingAnchor),
            childView.trailingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.trailingAnchor : trailingAnchor),
            childView.bottomAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.bottomAnchor : bottomAnchor)
        ])
    }
    
    /// 부모 뷰의 center로 배치하기
    ///
    /// - Parameters:
    ///   - childView: 하위 뷰
    ///   - width: 하위 뷰의 넓이 (default = 0)
    ///   - height: 하위 뷰의 높이 (default = 0)
    func addSubviewCenter(_ childView: UIView, width: CGFloat = 0, height: CGFloat = 0) {
        let viewWidth = width > 0 ? width : childView.frame.width
        let viewHeight = height > 0 ? height : childView.frame.height
        addSubview(childView)
        childView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            childView.centerXAnchor.constraint(equalTo: centerXAnchor),
            childView.centerYAnchor.constraint(equalTo: centerYAnchor),
            childView.widthAnchor.constraint(equalToConstant: viewWidth),
            childView.heightAnchor.constraint(equalToConstant: viewHeight)
        ])
    }
    
    /// 부모 뷰의 top에 배치하기
    ///
    /// - Parameters:
    ///   - childView: 하위 뷰
    ///   - height: 하위 뷰의 높이 (default = 0)
    ///   - offset: 부모 뷰의 top에서의 오프셋 (default = 0)
    ///   - isSafeArea: Safe Area 사용 기준 (default = false)
    func addSubviewTop(_ childView: UIView, height: CGFloat = 0, offset: CGFloat = 0, isSafeArea: Bool = false) {
        let viewHeight = height > 0 ? height : childView.frame.height
        addSubview(childView)
        childView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            childView.leadingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.leadingAnchor : leadingAnchor),
            childView.trailingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.trailingAnchor : trailingAnchor),
            childView.topAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.topAnchor : topAnchor, constant: offset),
            childView.heightAnchor.constraint(equalToConstant: viewHeight)
        ])
    }
    
    /// 부모 뷰의 bottom에 배치하기
    ///
    /// - Parameters:
    ///   - childView: 하위 뷰
    ///   - height: 하위 뷰의 높이 (default = 0)
    ///   - offset: 부모 뷰의 bottom에서의 오프셋
    ///   - isSafeArea: Safe Area 사용 기준 (default = false)
    func addSubviewBottom(_ childView: UIView, height: CGFloat = 0, offset: CGFloat = 0, isSafeArea: Bool = false) {
        let viewHeight = height > 0 ? height : childView.frame.height
        addSubview(childView)
        childView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            childView.leadingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.leadingAnchor : leadingAnchor),
            childView.trailingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.trailingAnchor : trailingAnchor),
            childView.bottomAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.bottomAnchor : bottomAnchor, constant: offset),
            childView.heightAnchor.constraint(equalToConstant: viewHeight)
        ])
    }
    
    /// 부모 뷰의 leading에 배치하기
    ///
    /// - Parameters:
    ///   - childView: 하위 뷰
    ///   - width: 하위 뷰의 넓이 (default = 0)
    ///   - offset: 부모 뷰의 leading에서의 오프셋
    ///   - isSafeArea: Safe Area 사용 기준 (default = false)
    func addSubviewLeading(_ childView: UIView, width: CGFloat = 0, offset: CGFloat = 0, isSafeArea: Bool = false) {
        let viewWidth = width > 0 ? width : childView.frame.width
        addSubview(childView)
        childView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            childView.leadingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.leadingAnchor : leadingAnchor, constant: offset),
            childView.topAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.topAnchor : topAnchor),
            childView.bottomAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.bottomAnchor : bottomAnchor),
            childView.widthAnchor.constraint(equalToConstant: viewWidth)
        ])
    }
    /// 부모 뷰의 trailing에 배치하기
    ///
    /// - Parameters:
    ///   - childView: 하위 뷰
    ///   - width: 하위 뷰의 넓이 (default = 0)
    ///   - offset: 부모 뷰의 trailing에서의 오프셋
    ///   - isSafeArea: Safe Area 사용 기준 (default = false)
    func addSubviewTrailing(_ childView: UIView, width: CGFloat = 0, offset: CGFloat = 0, isSafeArea: Bool = false) {
        let viewWidth = width > 0 ? width : childView.frame.width
        addSubview(childView)
        childView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            childView.trailingAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.trailingAnchor : trailingAnchor, constant: offset),
            childView.topAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.topAnchor : topAnchor),
            childView.bottomAnchor.constraint(equalTo: isSafeArea ? safeAreaLayoutGuide.bottomAnchor : bottomAnchor),
            childView.widthAnchor.constraint(equalToConstant: viewWidth)
        ])
    }
    
    /// 현재 뷰의 Autolayout 제약 조건 제거 (부모 뷰에서 제거)
    func removeConstraints() {
        if let superview = superview {
            for constraint in superview.constraints {
                if let first = constraint.firstItem as? UIView, first == self {
                    superview.removeConstraint(constraint)
                }
                
                if let second = constraint.secondItem as? UIView, second == self {
                    superview.removeConstraint(constraint)
                }
            }
        }
        removeConstraints(constraints)
        translatesAutoresizingMaskIntoConstraints = true
    }
    
    /// 현재 뷰의 Autolayout 제약 조건 제거 (모든 부모 뷰에서 제거)
    func removeAllConstraints() {
        var superview = self.superview
        while let view = superview {
            for constraint in view.constraints {
                if let first = constraint.firstItem as? UIView, first == self {
                    view.removeConstraint(constraint)
                }
                
                if let second = constraint.secondItem as? UIView, second == self {
                    view.removeConstraint(constraint)
                }
            }
            superview = view.superview
        }
        removeConstraints(constraints)
        translatesAutoresizingMaskIntoConstraints = true
    }

    /// Autolayout left 값 설정
    var leftConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .left && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout right 값 설정
    var rightConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .right && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout top 값 설정
    var topConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .top && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout bottom 값 설정
    var bottomConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .bottom && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout leading 값 설정
    var leadingConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .leading && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout trailing 값 설정
    var trailingConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .trailing && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout height 값 설정
    var heightConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .height && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout width 값 설정
    var widthConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .width && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout centerX 값 설정
    var centerXConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .centerX && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
    
    /// Autolayout centerY 값 설정
    var centerYConstraint: NSLayoutConstraint? {
        get { constraints.first { $0.firstAttribute == .centerY && $0.relation == .equal } }
        set { setNeedsLayout() }
    }
}
반응형
Posted by 까칠코더
,