본문 바로가기

학습 노트/iOS (2021)

167. Constraints with Code #5

Constraints with Code #5

 

Constraint animation

제약에 Animation을 추가해 본다.

//
//  AnimatingLayoutChangesViewController.swift
//  Constraints with Code Practice
//
//  Created by Martin.Q on 2021/12/20.
//

import UIKit

class AnimatingLayoutChangesViewController: UIViewController {
	@IBOutlet weak var pinkView: UIView!
	@IBOutlet weak var heightConstraint: NSLayoutConstraint!
	@IBOutlet weak var widthConstraint: NSLayoutConstraint!
	@IBOutlet weak var centerYConstraint: NSLayoutConstraint!
	@IBOutlet weak var centerXConstraint: NSLayoutConstraint!
	
	@IBAction func animate(_ sender: Any) {
		UIView.animate(withDuration: 0.3) { [weak self] in
			guard let strongSelf = self else { return }
			
			var frame = strongSelf.pinkView.frame
			let rnd = CGFloat(arc4random_uniform(91)) + 10
			frame.size = CGSize(width: rnd, height: rnd)
			
			strongSelf.pinkView.frame = frame
		}
	}
	
	override func viewDidLoad() {
        super.viewDidLoad()
    }
}

사용할 Scene과 코드는 위와 같다.
버튼을 클릭할 때마다, 분홍색 View의 높이와 너비를 무작위로 변경하고, Animation을 적용한다.

분홍색 View에는 높이와 너비 제약이 추가돼있고, 화면의 중앙에 배치될 수 있도록 수직과 수평 방향의 가운데 정렬 제약이 추가돼있다.
버튼을 누르면 Frame을 변경하는 Animation 코드가 구현돼있다.

현재 상태에선 잠시 변경됐다가 다시 원래의 크기로 돌아오는 것을 볼 수 있다.
이는 frame 속성을 변경하는 방식으로 동작을 구현했기 때문인데,
이는 Frame based 방식에서나 사용하던 방식이다.
Auto Layout이나 Adaptive Layout을 사용하는 지금에는 제약을 변경하는 방식으로 구현해야 한다.

@IBAction func animate(_ sender: Any) {
	UIView.animate(withDuration: 0.3) { [weak self] in
	guard let strongSelf = self else { return }
		
		strongSelf.widthConstraint.constant = CGFloat(arc4random_uniform(91)) + 10
		strongSelf.heightConstraint.constant = CGFloat(arc4random_uniform(91)) + 10
		strongSelf.centerXConstraint.constant = CGFloat(arc4random_uniform(101)) - 50
		strongSelf.centerYConstraint.constant = CGFloat(arc4random_uniform(101)) - 50
	}
}

이렇게 수정하면 너비와 높이는 10 ~ 100 사이의 무작위 값으로,
위치는 중앙을 기준으로 100 내에서 무작위 값으로 할당된다.

하지만 이번에는 Animation이 적용되지 않는다.
Auto Layout에서는 해당 방식으로 Animation을 적용할 수 없다.

@IBAction func animate(_ sender: Any) {
	
	widthConstraint.constant = CGFloat(arc4random_uniform(91)) + 10
	heightConstraint.constant = CGFloat(arc4random_uniform(91)) + 10
	centerXConstraint.constant = CGFloat(arc4random_uniform(101)) - 50
	centerYConstraint.constant = CGFloat(arc4random_uniform(101)) - 50
	
	UIView.animate(withDuration: 0.3) { [weak self] in
		guard let strongSelf = self else { return }
		
		strongSelf.view.layoutIfNeeded()
	}
}

이번에는 제약을 Animation 블록 밖에서 변경하고,
Animation 블록 안에서는 Rootview의 layoutIfNeeded 메서드를 호출한다.

이번엔 정상적으로 Animation이 적용됐다.

제약을 변경하고 Animation을 적용하고자 한다면 항상
제약을 먼저 변경하고, Animation 블록 내에서 layoutIfNeeded 메소드를 호출해야 한다.

Change CH & CR with code

Scene의 Label들에는 모든 방향으로 10pt의 제약이 추가돼있다.
보는 것과 같이 제대로 표시되지도 않고, 남는 공간에 대비해 Intrinsic 사이즈보다 어떤 Label이 커져야 할지 모호함이 발생한다.
CR과 CH를 코드로 변경해 해결해 본다.

//
//  CHCRViewController.swift
//  Constraints with Code Practice
//
//  Created by Martin.Q on 2021/12/20.
//

import UIKit

class CHCRViewController: UIViewController {
	@IBOutlet weak var topLabel: UILabel!
	@IBOutlet weak var bottomLabel: UILabel!
	
    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

코드는 위와 같다.

CHCR은 제약의 속성이 아닌 View의 속성이다.
해당 속성을 변경할 수 있는 메서드는 UIVIew 클래스에 구현돼있다.

UIView의 contentCompressionResistancePriority메서드는 View의 CR을 반환한다.
해당 메서드에 horizontal이나 vertical을 전달하면 해당되는 CR을 반환한다.
이때 반환되는 값의 형태는 UILayoutPriority 구조체이다.

setContentCompresstionResistancePriority메서드는 CR을 변경하는 메서드이다.
첫 번째 파라미터로 우선순위를 전달하고, 두 번째 파라미터로 방향을 전달한다.
마찬가지로 UILayoutPriority 구조체를 사용해 지정해야 한다.

CH는 이름만 다르고 동일하다.

//
//  CHCRViewController.swift
//  Constraints with Code Practice
//
//  Created by Martin.Q on 2021/12/20.
//

import UIKit

class CHCRViewController: UIViewController {
	@IBOutlet weak var topLabel: UILabel!
	@IBOutlet weak var bottomLabel: UILabel!
	
    override func viewDidLoad() {
        super.viewDidLoad()
		
		let priority = UILayoutPriority(250)
		topLabel.setContentHuggingPriority(priority, for: .vertical)
    }

}

수정한 코드와 결과는 위와 같다.
CH 우선순위가 낮아진 topLabel이 제약을 유지한 채 나머지 공간을 채우고 있다.

'학습 노트 > iOS (2021)' 카테고리의 다른 글

169 ~ 170. Timer & Runloop and Concurrency Programming  (0) 2021.12.24
168. Debugging Auto Layout  (0) 2021.12.21
166. Constraints with Code #4  (0) 2021.12.20
165. Constraints with Code #3  (0) 2021.12.19
164. Constraints with code #2  (0) 2021.12.17