Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
UIKit/AutoLayout

9. Dynamic Stack View_ Code

by Toughie 2023. 3. 27.

애플 하면 부드러운 애니메이션 아니겠는가..

스택뷰를 코드로 작성해 보고, 애니메이션을 통해 부드럽게 추가/제거 하는 연습을 해봤다.

(애니메이션을 적용하지 않으면 그냥 툭 툭 뷰가 추가/제거 된다. 별로 보기 안좋다.)

아래는 .gif라 좀 끊기지만 시뮬레이터에서는 부드럽게 잘 작동한다.

//
//  StackViewController.swift
//  codeLayout
//
//  Created by Toughie on 2023/03/27.
//

import UIKit

class StackViewController: UIViewController {
    
    var vertical: UIStackView = UIStackView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        vertical.axis = .vertical
        vertical.translatesAutoresizingMaskIntoConstraints = false
        vertical.spacing = 10
        vertical.distribution = .fillEqually
        view.addSubview(vertical)
        
        //버튼을 묶을 HStack
        
        let horizontal = UIStackView()
        horizontal.axis = .horizontal
        horizontal.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(horizontal)
        
        let addButton = UIButton()
        addButton.setTitle("Add", for: .normal)
        addButton.setTitleColor(.blue, for: .normal)
        addButton.addTarget(self,
                            action: #selector(addView),
                            for: .touchUpInside)
        
        let removeButton = UIButton()
        removeButton.setTitle("Remove", for: .normal)
        removeButton.setTitleColor(.red, for: .normal)
        removeButton.addTarget(self,
                               action: #selector(removeView),
                               for: .touchUpInside)
        
        horizontal.addArrangedSubview(addButton)
        horizontal.addArrangedSubview(removeButton)
        
        horizontal.distribution = .fillEqually
        
        horizontal.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        horizontal.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        horizontal.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        
        vertical.leadingAnchor.constraint(equalTo: horizontal.leadingAnchor).isActive = true
        vertical.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        vertical.trailingAnchor.constraint(equalTo: horizontal.trailingAnchor).isActive = true
        vertical.bottomAnchor.constraint(equalTo: horizontal.topAnchor).isActive = true
    }
    
    @objc func addView() {
        let view = UIView()
        let colors: [UIColor] = [UIColor(ciColor: .red),
                                 UIColor(ciColor: .magenta),
                                 UIColor(ciColor: .blue),
                                 UIColor(ciColor: .yellow),
                                 UIColor(ciColor: .gray),
                                 UIColor(ciColor: .cyan),
                                 UIColor(ciColor: .green)]
        
        
        let randomInt = Int.random(in: 0..<colors.count)
        
        view.backgroundColor = colors[randomInt]
        view.isHidden = true //우선 뷰를 숨겨뒀다가..
        vertical.addArrangedSubview(view)
        UIView.animate(withDuration: 0.3) {
            view.isHidden = false
        }
        
        
        print("add")
    }
    
    @objc func removeView() {
        guard let last = vertical.arrangedSubviews.last else { return }
        
        UIView.animate(withDuration: 0.3) {
            last.isHidden = true
        } completion: { (_) in
            self.vertical.removeArrangedSubview(last)
        }
    }
}

원래는 단색의 뷰가 추가되는 예시였는데.. 심심해서 알록달록하게 해보려고 코드를 수정했다.

분명 더 좋게 짤 수도 있겠지만.. 그리 중요한 부분이 아니라 생각해서

그냥 컬러를 담는 배열을 만들고

랜덤 숫자를 뽑아

배열에 서브스크립트로 접근하는 방식이다.

UIColor타입을 배열에 어떻게 담지? 했는데 아래와 같은식으로 해도 일단 잘 된다.

UIColor(ciColor: .cyan)

 

 

 

애니메이션을 적용하기 전에 view를 숨기는 .isHidden 프로퍼티가 있음을 기억하자.

또한 버튼에 기능을 연결하기 위해 필요한 셀렉터에 대해 간단하게 알아보자.

#selector

주로 특정 이벤트를 함수/메서드에 연결시키는 방법을 말한다.

@objc func doSomething() {
	print("I like Swift")
}

button.addTarget(self, action: #selector(doSomething), for: touchUpInside)

셀렉터는 어떤 함수/메서드를 가리키는 연결고리 정도로 생각하면 좋다.

 

다만 selector안에 들어가는 함수/메서드 앞에는 @objc 어트리뷰트를 붙여줘야 한다.

@objc는 Swift 메서드, 속성 또는 클래스가 Objective-C 코드임을 나타내는 것이다.

이전 옵젝씨에서 사용하던 메서드나 프로퍼티를 사용할 때 필요.(대표적으로 셀렉터 같이)

 

옵젝C에서 Swift로 넘어가는 과정에서 남은 잔재? 정도로 보인다.

셀렉터 몇 번 써보다 보면 그냥 자동으로 @objc 붙여야지 라고 생각하게 된다.

 

 

[학습 소스]

공식문서, 야곰 오토레이아웃 정복하기 강의

https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html

https://yagom.net/courses/autolayout/

'UIKit > AutoLayout' 카테고리의 다른 글

11. Safe Area , Layout Margins  (0) 2023.03.27
10. Size Class ?  (0) 2023.03.27
8. 코드로 오토레이아웃 잡기  (0) 2023.03.26
7. SuperView, Safe Area  (0) 2023.03.26
6. Debugging Auto Layout  (0) 2023.03.26