#13 Drawing & Custom Graphics
더 복잡한 앱을 개발하기 시작하면 SwiftUI가 제공하는 기본 제공 컨트롤보다 더 많은 custom 을 위한 유연함이 필요하다.
SwiftUI는 앱 내에서 그래픽 생성을 지원하는 풍부한 라이브러리를 제공한다.
그래픽은 사용자에게 정보를 효율적이고 이해하기 쉽게 전달한다.
예를 들어, 동일한 정보를 그래픽으로 보는게 읽는 것 보다 시간이 덜 걸린다.
이 장에서는 공항 앱을위한 몇 가지 awards 그래픽을 만들어 SwiftUI에서 그래픽을 사용해본다.
Creating shapes
starter project 에는 작은 공항을 위한 앱이 있다.
3개의 award 뱃지를 만들 것 이다.
뱃지를 그릴 FirstVisitAward.swift 파일을 만들고 AirportAwards.swift 에 FirstVisitAward를 scrollView 안에 넣어준다.
SwiftUI에서 기본 drawing structure은 Shape 가 있다. (simple primitive shape set)
먼저 사각형을 추가하기 위해 FirstVisitAward.swift 에서 기본 Text를 지우고 Rectagle() 로 바꾼다.
이 사격형은 SwiftUI 에서 도형을 그릴때 default 값이 무엇인지 보여주고 있다.
만약 명시적으로 fill 이나 strock 를 알려주지 않으면 shape 는 현재 foreground color 로 채워질 것이다. (Color.primary)
항상 다크모드에서도 어떻게 보여지는지 확인해야 한다.
.environment(\.colorScheme, .dark)
Xcode 11.4 에서 enviroment 를 바꿔도 background 가 바뀌지 않는 버그가 있어서 preview 를 NavigationView 로 wrap 해서 확인한다.
NavigationView wrapping 해도 바탕 흰색인데..?
Rectangle()
.fill(Color.blue)
.frame(width: 200, height: 200)
defualt 를 override 해서 light 모드던 dark 모드던 같은 색을 띈다.
여기서 modifier 순서가 중요한데 fill은 frame 전에 위치해야 한다.
border(_:width:)를 통해 외곽선을 만들 수 도 있다.
Using gradients
solid color 대신 gradient fill을 사용할 것 이다.
linear-gradient 색들 사이를 부드럽게 전환하며 보여준다. startPoint 와 endPoint 는 UnitPoint 구조체를 사용한다.
이 구조체는 값의 범위를 0 부터 1의 범위로 만들어 정확한 값 없이 범위를 쉽게 정의할 수 있게 해준다.
UnitPoints origin 좌표는 (0,0) 으로 상단왼쪽에 위치하고 오른쪽 아래로 갈수록 증가한다.
starting point 를 bottom left corner 로 정하고 endpoint 를 top right corner 로 지정했다.
linear-gradient 는 무조건 0부터 1까지의 범위로 강제하진 않는다. 시작점과 끝점을 원하는 아무데나 view 밖에서도 정의할 수 있다.
*이 point들은 color의 끝이 아닌 transition의 끝을 뜻한다. Color는 이러한 지점을 지나서 end color까지 진행된다.
Rotating shapes
이번엔 만든 사각형을 회전시키며 새로운 사각형 2개를 만들어 본다.
ForEach 로 만든다.
- 3개의 사각형을 담을 ZStack을 만든다. ZStack은 content를 배치가고 양 축에 정렬한다.
- ForEach 를 통해 순회하며 (0, 1, 2) index 인 i 를 전달한다.
- 사각형을 만드는 코드는 변함이 없지만 i*60 값으로 회전시킨다,
Adding Images
drawing 과 image를 합치는 건 공수를 줄여준다.
크기가 정해져 있는 사각형을 만드는 건 image를 다루는 것을 더 어렵게 만든다.
더 나은 옵션으로는 frame 을 채워서 모든 크기에 맞게 조정하는 것이다. 적응형 view를 만든다
frame modifier를 rectangle 에서 없애고 preview 에는 frame 을 적용해준다.
그리고 image에 resizeable modifier 를 적용하고 회전과 opacity 를 준다.
Scaling drawings in views
실행해보면 뱃지가 타이블과 겹치는 문제가 있다.
회전된 shape 가 사각형 내에 위치하도록 사이즈를 조정해야 한다.
- GeometryReader container는 내부 view 의 size 와 shape 를 가져올 수 있게 하여 constants에 의존하지 않고 코드를 작성할 수 있게 한다.
- geometry의 size 프로퍼티를 사용해서 view 의 너비와 높이를 가져온다.
그리고 0.7만큼 scale 을 낮춰서 frame 을 회전해도 사각형 안에 위치하도록 만든다.
SwiftUI는 바로바로 preview 를 통해 확인할 수 있데 해준다. - image 또한 scaleEffect로 같은 scale 만큼 줄인다.
Other shapes
SwiftUI 는 다른 모양도 제공한다.
- Circle: 원의 반지름은 사각형 frame 의 짧은 모서리의 반에 해당한다
- Ellipse: frame 에 맞게 타원이 만들어 진다.
- Rounded Rectangle: frame 에 맞게 타원이 만들어 진다.
- Capsule: rounded rectangle 인데 corner radius 가 사각형의 짧은 모서리의 절반이다.
scale 이나 다른 effect 는 Rectangle 과 동일하게 적용된다.
복잡한 그림을 그릴땐 Paths 를 이용해라
Drawing lines with paths
custom shape 를 만들고 싶을 때 Paths를 사용한다.
OverNightParkAward.swift 파일을 만들어서 도형을 그려본다.
이전과 동일하게 GeometryReader로 frame 에 관계없는 동적인 view 를 만들어준다.
처음 세 줄은 너비와 높이 사이의 더 작은 치수로 크기를 결정한다.
그런 다음 크기에 따라 근거리 및 원거리 값을 정의한다.
마지막으로 Path 에 Color를 채워주면
.fill(Color.init(red: 0.4, green: 0.4, blue: 0.4))
Drawing dashed line
도로처럼 보이게 하기위해 중간에 점선을 그을 것 이다.
도로 shape 를 ZStack 으로 감싸고 아래에 점섬을 위한 코드를 작성한다.
차량 이미지도 추가한다.
Drawing arcs and curves
path 는 선을 그리는데 적합하다. 곡선을 그릴려면 arcs 와 quadratic curves 를 사용해야 한다.
AirportMealAward.swift 파일을 만든다.
Drawing quadratic curves
quadratic math (이차방정식) 공식에서 이름을 따왔다. SwiftUI는 수학적인 부분을 담당한다.
이차곡선과 같이 3번째 점(control point) 로 당겨진 곡선을 생각하면 된다. 각 끝에서 곡선은 control point에 그려진 선과 평행하게 시작하고 모든 점 사이에서 부드럽게 곡선을 그린다.
addArc 메서드는 원의 부분을 그린다. 원의 중신과 반지름을 정하고 start angle 과 end angle, 시계방향을 알려주면 된다.
Fixing performance problems
SwiftUI 는 그래픽과 애니메이션을 CoreGraphics로 렌더링한다.
각각의 view를 필요할 때 그리는데 현재의 Apple 기기의 하드웨어는 여러개의 뷰를 성능저하 없이 처리할 수 있다.
하지만 어느 정도를 넘어서면 시스템에 과적해서 성능 저하를 확인할 수 있다.
만약 발생하면 drawingGroup modifier를 사용할 수 있다.
이 modifier는 SwiftUI 에게 view 내용을 off screen image 로 먼저 바꿔 놓게 해준다.
이 offscreen composition은 Metal 을 사용한다. 그래서 복잡한 화면에 대해 높은 성능을 낸다.
offscreen composition 은 오버헤드를 만들어 간단한 그래픽에서는 오히려 더 느리다
Key points
- shape는 간단한 control 을 그릴 수 있는 방법을 제공한다.
기본적으로 Rectangle, Circle, Ellipse, RoundedRectangle, Capsule 이 있다. - 디폴트로 Shape 에는 foreground color 가 입혀진다.
- Shape는 solid 나 gradient color 로 채울 수 있다.
- Gradient 는 transition으로 linear, radial, angular 이 있다,
- rotationEffect는 shape 를 축에 따라 회전시킨다.
- ZStack 은 공통되는 축에 따라 그래픽을 함친다.
그래픽과 이미지를 섞을 수 있다. - GeometryReader는 container에 맞게 그래픽이 그려질 수 있도록 해준다.
- Paths는 기본 Shape 보다 더 복잡한 커브나 아치가 들어간 drawing 을 그릴때 사용한다.
- 셰이프와 마찬가지로 셰이프를 수정하고 패스를 채울 수 있습니다.
- drawGroup 은 무거운 그래픽 view의 성능을 향상시킬 수 있지만 오히려 단순한 view 에서는 느려진다