Warning 해결
현재 실행을 하게되면
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
이런식으로 Auto Layout에 대한 워닝이 발생한다.
에러가 발생하는 이유는 Vertical StackView 때문인데
여기안에 UIView를 하나 더 추가를 해줘야한다.
설명이 이해가 안가서 나중에 다시 알아봐야할거같다.
이렇게 UIView하나가 새로 생기면서 해결이 되긴 했다.
폰트 적용 틀 만들어두기.
지원버전은 사이트참고
struct ThemeFont {
// AvenirNext
static func regular(ofSize size: CGFloat) -> UIFont {
return UIFont(name: "AvenirNext-Regular", size: size) ?? .systemFont(ofSize: size)
}
static func bold(ofSize size: CGFloat) -> UIFont {
return UIFont(name: "AvenirNext-Bold", size: size) ?? .systemFont(ofSize: size)
}
static func demibold(ofSize size: CGFloat) -> UIFont {
return UIFont(name: "AvenirNext-Demibold", size: size) ?? .systemFont(ofSize: size)
}
}
LogoView 디자인
이건 완성된 코드하나도 될 것 같다.
이렇게 디자인 할 생각을 하지 못했는데 새로운 강의를 들으면서 제대로 배웠다.
구현할 View를 먼저 클래스 파일로 만들고 거기서 디자인을 한다.
이게 포인트다.
class LogoView: UIView {
private let imageView: UIImageView = {
let view = UIImageView(image: .init(named: "icCalculatorBW"))
view.contentMode = .scaleAspectFit
return view
}()
private let topLabel: UILabel = {
let label = UILabel()
let text = NSMutableAttributedString(string: "Mr TIP",attributes: [.font: ThemeFont.demibold(ofSize: 16)])
text.addAttributes([.font: ThemeFont.bold(ofSize: 24)], range: NSMakeRange(3, 3)) // TIP부분 더 강조
label.attributedText = text
return label
}()
private let bottomLabel: UILabel = {
LabelFactory.build(
text: "Calculator",
font: ThemeFont.demibold(ofSize: 20),
textAlignment: .left)
}()
private lazy var vStackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [
topLabel,
bottomLabel
])
view.axis = .vertical
view.spacing = -4
return view
}()
private lazy var hStackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [
imageView,
vStackView
])
view.axis = .horizontal
view.spacing = 8
view.alignment = .center
return view
}()
init () {
super.init(frame: .zero)
layout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func layout() {
addSubview(hStackView)
hStackView.snp.makeConstraints { make in
make.top.bottom.equalToSuperview()
make.centerX.equalToSuperview()
}
imageView.snp.makeConstraints { make in
make.height.equalTo(imageView.snp.width)
}
}
}
// LabelFactory
struct LabelFactory {
// 기본적인 틀을 구조화
static func build(
text: String?,
font: UIFont,
backgroundColor: UIColor = .clear,
textColor: UIColor = ThemeColor.text,
textAlignment: NSTextAlignment = .center) -> UILabel {
let label = UILabel()
label.text = text
label.font = font
label.backgroundColor = backgroundColor
label.textColor = textColor
label.textAlignment = textAlignment
return label
}
}
완성.
ResultView 추가
위와 상동
다만 하나 알아두면 좋을 것은
private lazy var hStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [
AmountView(),
UIView(), // 사이에 끼워줌.
AmountView()
])
stackView.axis = .horizontal
stackView.distribution = .fillEqually
return stackView
}()
이렇게 가운데에 UIView 를 끼워주고 3분할을 정확하게 해주었다는 것.
또 하나 배웠다.
shadow효과를 위한 extension 생성
extension UIView {
func addShadow(offset: CGSize, color: UIColor, radius: CGFloat, opacity: Float) {
layer.cornerRadius = radius
layer.masksToBounds = false
layer.shadowOffset = offset
layer.shadowColor = color.cgColor
layer.shadowRadius = radius
layer.shadowOpacity = opacity
let backgroundCGColor = backgroundColor?.cgColor
backgroundColor = nil
layer.backgroundColor = backgroundCGColor
}
}
가운데 선과 아래 View 사이 패딩 추가
private func buildSpacerView(height: CGFloat) -> UIView {
let view = UIView()
view.heightAnchor.constraint(equalToConstant: height).isActive = true
return view
}
이렇게 하나 만들어주고
horizontalLineView,
buildSpacerView(height: 0),
hStackView
높이 0짜리를 하나 사이에 끼워 넣어주면서 패딩이 자연스럽게 된다.
완성
AmountView 디자인
class AmountView: UIView {
private let title: String
private let textAlignment: NSTextAlignment
private lazy var titleLabel: UILabel = {
LabelFactory.build(
text: title,
font: ThemeFont.regular(ofSize: 18),
textColor: ThemeColor.text,
textAlignment: textAlignment)
}()
private lazy var amountLabel: UILabel = {
let label = UILabel()
label.textAlignment = textAlignment
label.textColor = ThemeColor.primary
let text = NSMutableAttributedString(
string: "$0",
attributes: [
.font: ThemeFont.bold(ofSize: 24)
])
text.addAttributes([
.font: ThemeFont.bold(ofSize: 16)
], range: NSMakeRange(0, 1))
label.attributedText = text
return label
}()
private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [
titleLabel,
amountLabel
])
stackView.axis = .vertical
return stackView
}()
// custom Initializer
init(title: String, textAlignment: NSTextAlignment) {
self.title = title
self.textAlignment = textAlignment
super.init(frame: .zero)
layout()
}
//
// override init(frame: CGRect) {
// super.init(frame: frame)
// layout()
// }
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func layout() {
addSubview(stackView)
stackView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}
처음에 AmountView를 같은걸 해놔서 똑같은 뷰가 두개가 되어있었는데,
이것을 Custom Initializer를 통해 text와 문자 배열을 하게 설정을 한다.
// custom Initializer
init(title: String, textAlignment: NSTextAlignment) {
self.title = title
self.textAlignment = textAlignment
super.init(frame: .zero)
layout()
}
// origin initializer -> Don't use this method
override init(frame: CGRect) {
super.init(frame: frame)
layout()
}
// resultview의 일부
private lazy var hStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [
AmountView( // modified
title: "Total Bill",
textAlignment: .left),
UIView(), // 사이에 끼워줌.
AmountView( // modified
title: "Total Tip",
textAlignment: .right)
])
stackView.axis = .horizontal
stackView.distribution = .fillEqually
return stackView
}()
뭔가 Code로 UIdesign 하는것에 신세계를 경험하게 된다.
너무 길어지니 파트2는 여기까지
PREVIOUSTip-Calculator (1)