본문 바로가기

도서/SwiftUI by Tutorials

[SwiftUI by Tutorials] Chapter 05: Intro to Controls: Text & Image

반응형

1. Text

표시할 텍스트라는 단일 매개 변수를 사용한다.

Text("Welcome to Kuchi")

 

Modifiers

텍스트를 표시했으니, 자연스러운 다음 단계는 모양을 변경하는 것이다.

크기, 무게, 색상, 기울임 꼴 등과 같은 다양한 옵션을 사용하여 화면에서 텍스트가 표시되는 방식을 수정할 수 있다.

 

60포인트로 텍스트를 더 크게 만들려면?

Text("Welcome to Kuchi")
	.font(.system(size: 60))

 

추가적으로 텍스트를 굵게 하려면?

Text("Welcome to Kuchi")
	.font(.system(size: 60))
	.bold()

 

추가적으로 글씨색을 빨간색으로 하려면?

Text("Welcome to Kuchi")
	.font(.system(size: 60))
	.bold()
	.foregroundColor(.red)

 

텍스트를 두 줄로 하려면?

Text("Welcome to Kuchi")
	.font(.system(size: 60))
	.bold()
	.foregroundColor(.red)
	.lineLimit(2)

 

마지막으로 left-align 하려면?

Text("Welcome to Kuchi")
	.font(.system(size: 60))
	.bold()
	.foregroundColor(.red)
	.lineLimit(2)
	.multilineTextAlignment(.leading)

 

 

마지막 두 단계에서 뚜렷한 결과가 나오지 않는다는 것을 알 수 있다.

사실 .lineLimit의 기본값은 nil(줄 제한 없음)이고,

multilineTextAlignment의 기본값은 .leading이다.

 

UI 속성의 기본값은 변경되지 않는다고 가정하는 것이 안전하지만 SwiftUI 베타 릴리스 단계에서 언급했듯이 향후 변경될 수 있다.

또한 .lineLimit의 경우 화면 공간을 보존하기 위해 최대 2줄로 제한할 수 있다.

 

Text는 간단한 컴포넌트이지만 수정자가 매우 많다.

SwiftUI가 제공하는 수정자에는 두 가지 범주가 있다.

  1. 모든 View에서 사용할 수 있는 View Protocol과 함께 번들로 제공되는 수정자
  2. 특정 유형의 수정자는 해당 유형의 인스턴스에만 사용할 수 있음

 

Are modifiers efficient?

모든 수정자는 새로운 View를 반환하기 때문에 이 프로세스가 실제로 가장 효율적인 방법인지 궁금할 것이다.

SwiftUI는 수정자를 호출할 때마다 새로운 뷰를 뷰에 추가한다. 뷰 스택을 생성하는 재귀 프로세스이다.

 

직관적으로 자원 낭비로 보인다.

진실은 SwiftUI가 이 스택을 뷰의 실제 랜더링에 사용되는 효율적인 데이터 구조로 평면화한다는 것이다.

제한 없이 뷰의 효율성에 영향을 미칠 염려 없이 필요한 만큼 수정자를 자유롭게 사용할 수 있다.

 

Order of modifiers

수정자를 호출하는 순서가 중요한가?

대답은 "예"이지만 많은 경우에 "상관없다"도 답이 된다.

 

bold를 적용하고 foreground color를 설정하는 것과

foreground color를 설정하고 bold를 적용하는 것은 동일하다.

 

하지만 background color를 적용하고 padding을 적용하는 것과

padding을 적용하고 background color를 적용하는 것은 다른 결과가 나오게 된다.

 

padding을 먼저 적용하면 더 큰 View를 만든 다음 background color를 적용한다.

결과가 다른 것을 즉시 알 수 있다.

패딩을 적용하기 전과 후 다른 배경색을 설정하면 더 명확하게 보인다.

Text("Welcome to Kuchi")
	.background(Color.yellow)
	.padding()
	.background(Color.red)

 

2. Image

Changing the image size

수정자를 사용하지 않고 이미지를 생성하면 SwiftUI는 이미지를 기본 해상도로 렌더링하고 이미지의 종횡비를 유지한다.

 

resizable 수정자를 적용하지 않으면 이미지가 기본 크기를 유지한다.

이미지 크기를 직간접적으로 변경하는 수정자를 적용한다면 적용된 것처럼 보이지만, 이미지 자체에는 적용되지 않으므로 원래 크기가 유지된다.

 

system table 이미지를 추가하고 너비와 높이 30으로 지정하면 다음과 같이 나온다.

 

var body: some View {
	Image(systemName: "table")
    	.frame(width: 30, height: 30)
}

 

resizable 수정자를 추가하면 다음과 같이 나온다.

var body: some View {
	Image(systemName: "table")
    	.resizable()
    	.frame(width: 30, height: 30)
}

 

3. Brief overview of stack views

View의 body 속성은 하나의 하위 뷰만 예상한다.

따라서 View에 하나 이상의 하위 뷰를 포함시키려면 컨테이너 View에 의존해야 한다.

가장 기본적인 컨테이너 뷰는 UIKit의 UIStackView에 해당하는 Stack이다.

 

  • HStack: 하위 요소를 수평으로 나열하는 컨테이너 뷰
  • VStack: 하위 요소를 수직으로 나열하는 컨테이너 뷰
  • ZStack: 하위 요소를 겹쳐서 나열하는 컨테이너 뷰

 

Splitting Text

VStack {
	Text("Welcome to")
		.font(.system(size: 30))
		.bold()
		.foregroundColor(.red)
		.lineLimit(2)
		.multilineTextAlignment(.leading)
	Text("Kuchi")
		.font(.system(size: 30))
		.bold()
		.foregroundColor(.red)
		.lineLimit(2)
		.multilineTextAlignment(.leading)
}

위 두 개의 Text 뷰를 보면 마지막 세 개의 수정자가 동일하다는 것을 알 수 있다.

View에서 구현된 수정자로 개별 View 대신 상위 Stack 뷰에 적용하여 코드를 리팩터링 할 수 있다.

 

VStack {
	Text("Welcome to")
		.font(.system(size: 30))
		.bold()
	Text("Kuchi")
		.font(.system(size: 30))
		.bold() 
}
.foregroundColor(.red)
.lineLimit(2)
.multilineTextAlignment(.leading)

매우 강력한 기능이다. 컨테이너 뷰가 있고 모든 하위 보기에 수정자를 적용하려는 경우 컨테이너에 적용하기만 하면 되기 때문이다.

(font, bold는 동일하긴 하지만 Text의 수정자로 컨테이너에 적용할 수 없다.)

 

Accessibility with fonts

Apple은 가능하면 text font 하드 코딩을 하지 않는 것을 권장한다.

.system(size: 30) 대신, .headline, .largeTitle과 같은 스타일을 사용하는 이유다.

size class를 만들어 사용한다면 앱에 사용된 모든 글꼴을 참조 크기와 관련하여 자유롭게 늘리거나 줄일 수 있다.

참조 크기가 증가하면 모든 글꼴이 비례적으로 커지고. 감소하면 반대로 작아진다.

 

Label: Combining Image and Text

이미지와 텍스트는 나란히 사용되는 경우가 많다. HStack을 이용하는 방법도 있지만 Apple에서 단순화하기 위해 Label을 제공했다.

   Label("Welcome", systemImage: "hand.wave")

이 외에도 Text와 Image를 사용자가 커스텀하여 적용할 수 있다.

init(title: () -> Title, icon: () -> Icon)

 

예시

Label { // 1
	VStack(alignment: .leading) {
		Text("Welcome to")
			.font(.headline)
			.bold()
		Text("Kuchi")
			.font(.largeTitle)
			.bold() 
	}
	.foregroundColor(.red)
	.lineLimit(2)
	.multilineTextAlignment(.leading)
	.padding(.horizontal)
} icon: {
	// 2
	Image(systemName: "table")
		.resizable()
		.frame(width: 30, height: 30)
		.overlay(Circle().stroke(Color.gray, lineWidth: 1))
		.background(Color(white: 0.9))
		.clipShape(Circle())
		.foregroundColor(.red)
}

  1. 텍스트 컴포넌트 (VStack에 포함된 두 개의 Text로 구성)
  2. 이미지 컴포넌트

 

결과적으로 vertical align이 안되어 있다.

문제를 해결하기 위해서는 Label의 내부 컴포넌트 정렬하는 방식을 재정의해야 한다.

Label에 스타일을 적용할 순 있지만, 적합한 것은 없어 보인다.

 

스타일

  1.  DefaultLabelStyle: 기본 스타일로 title과 image 모두 표시
  2. IconOnlyLabelStyle: title 없이 icon만 표시
  3. TitleOnlyLabelStyle: icon 없이 title만 표시

적합한 것이 없다고 슬퍼하지 않아도 된다. 직접 구축하면 된다.

import SwiftUI
struct HorizontallyAlignedLabelStyle: LabelStyle {
	func makeBody(configuration: Configuration) -> some View {
		HStack {
			configuration.icon
			configuration.title
		}
	}
}


// Usage
.labelStyle(HorizontallyAlignedLabelStyle())

 

반응형