티스토리 뷰

iOS

[IOS AUTO LAYOUT] Dynamic Stack View

rhinoPHS 2018. 7. 18. 19:49

[IOS AUTO LAYOUT] Dynamic Stack View




코드로 스택뷰를 만들고 추가, 삭제 하면서 위와 같은 UI를 만들어 본다. (notice, 위 UI는 table view로 하는 게 더 좋다.)

1.스크롤뷰를 뷰컨트롤러에 위치시키고 Safe Area에 Constraints를 걸어준다
  - 보기 편하게 leading과 trailing은 8정도 띄어준다
  - add button을 위해서 bottom은 20정도 띄어준다






2 수직 스택뷰를 스크롤 뷰 하위뷰로 추가하고 scroll view에 constraints를 걸어준다
   - 네 방향 다 0으로 걸어주고
   - width 를 같게 설정한다 ( 스택뷰는 자체적으로 intrinsic content 사이즈가 없으므로)
   - height은 동적으로 늘어날 거라서 생략한다
   - 오류가 난다. 스택뷰에 하위 뷰가 없어서 그렇다 




3 스택뷰에 버튼 하나를 추가한다
   - 에러가 사라진다 



4 아래 처럼 스택뷰 속성을 바꾼다

Stack

Axis

Alignment

Distribution

Spacing

Stack View

Vertical

Fill

Equal Spacing

0


5 뷰컨트롤러에 커스텀뷰컨트롤러를 만들고 연결해준다


6 스크롤 뷰와 스택뷰를 커스텀뷰컨터롤러에 연결한다.


import UIKit


class DynamicStackViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!

    @IBOutlet weak var stackVIew: UIStackView!

    

    override func viewDidLoad() {

        super.viewDidLoad()

    }

    ......

}


7 add Button을 클릭했을 때 stack view를 추가하는 코드를 작성한다.


    // MARK : add Entry Methods

    @IBAction func addEntry(_ sender: UIButton) {

        

        // stack view에 있는 add button을 가져온다.

        guard let addButtonContainerView = stackVIew.arrangedSubviews.last else {

            fatalError("Expected at least one arranged view in the stack view")

        }

        

        // add button 한 칸 앞 index를 가져 온다

        let nextEntryIndex = stackVIew.arrangedSubviews.count - 1

        

        // scrollview의 스크롤이 이동할 위치계산

        // 현 위치에서 add button의 높이 만큼 이레러

        let offset = CGPoint(x: scrollView.contentOffset.x, y:

scrollView.contentOffset.y + addButtonContainerView.bounds.size.height)

        

        // stackview를 만들어서 안 보이게 처리

        let newEntryView = createEntryView()

        newEntryView.isHidden = true

        

        // 만들어진 stack view를 add button앞에다가 추가

        stackVIew.insertArrangedSubview(newEntryView, at: nextEntryIndex)

        

        // 0.25초 동안 추가된 뷰가 보이게 하면서 scrollview의 스크롤 이동

        UIView.animate(withDuration: 0.25) {

            newEntryView.isHidden = false

            self.scrollView.contentOffset = offset

        }

    }


8 Delete button을 클릭했을 때 stack view를 제거하는 코드를 작성한다.


    // 액션을 코드로 추가해줘야 하기 때문에 @objc를 붙여줌

    @objc func deleteStackView(sender: UIButton) {

        // 클릭 했을 때 버튼의 슈퍼뷰, 즉 버튼이 속해있는 stack view를 가지고 온다

        guard let entryView = sender.superview else { return }

        

        // 0.25동안 그 스택뷰를 안 보이게 하고

        // 완료하면 view 계층구조에서 제거한다

        // view 계층구조에서 제거하면 stackviewe에 arragedSubview에서도 자동적으로 제거됨

        UIView.animate(withDuration: 0.25, animations: {

            entryView.isHidden = true

        }, completion: { _ in

            entryView.removeFromSuperview()

        })

    }



9 스택뷰를 만드는 createEntryView함수를 만든다.


// 수직 스택뷰 안에 들어갈 수평 스택뷰들 만든다.

    private func createEntryView() -> UIView {

        // 현재날 짜는 짧게(M/D/Y) 가져온다

        let date = DateFormatter.localizedString(from: Date(), dateStyle: .short, timeStyle: .none)

        

        // uuid를 가져온다

        let number = NSUUID().uuidString

        

        // 스택뷰를 만들고

        // 각 속성을 아래와 같이 한다.

        // IB에서 하는 것과 같다

        let stack = UIStackView()

        stack.axis = .horizontal

        stack.alignment = .center

        stack.distribution = .fill

        stack.spacing = 8

        

        // 날짜르 표시해줄 Label를 만든다

        let dateLabel = UILabel()

        dateLabel.text = date

        dateLabel.font = UIFont.preferredFont(forTextStyle: .body)

        

        

        // uuid를 만들 Label을 만든다

        let numberLabel = UILabel()

        numberLabel.text = number

        numberLabel.font = UIFont.preferredFont(forTextStyle: .headline)

        

        

        // 이 label의 horizontal contenthugging을 249, compressionResistance 749로 해서 stackview의 남은 공간을 꽉 채우게 한다.

        numberLabel.setContentHuggingPriority(UILayoutPriority.defaultLow - 1.0, for: .horizontal)

        numberLabel.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh - 1.0, for: .horizontal)

        

        // 삭제 버튼을 만든다

        let deleteButton = UIButton(type: .roundedRect)

        deleteButton.setTitle("Delete", for: .normal)

        // 삭제버튼이 눌렸다가 떨어질 때 deleteStackView를 호출하게끔 연결한다.

        deleteButton.addTarget(self, action: #selector(deleteStackView(sender:)), for: .touchUpInside)

        

        //stack 뷰에 차례대로 쌓는다.

        stack.addArrangedSubview(dateLabel)

        stack.addArrangedSubview(numberLabel)

        stack.addArrangedSubview(deleteButton)

        

        return stack

    }


- 여기까지 런타임에 스택뷰를 만들고 추가 삭제 하는 것을 했다.


- 추가적으로 알아야 할 것


- stack view에 하위뷰를 hidden시키면 안보이긴 하지만 여전히 스택뷰에 존재한다. 다른 뷰 레이아웃에 영향을 주지 않는다.


stack view에 하위뷰를 추가시키면 자동적으로 view hierarchy에 추가 된다


- removeArragedSubview(view:)를 통해서 하위뷰를 삭제하면 자동적으로 (view hierarchy에서 삭제가 안 된다 하지만 - removeFromSuperview를 통해서 뷰를 view hierarchy에서 제거하면 arranged views에서 삭제 된다


- 결과





반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함