SwiftUI

Circle Indicator 만들기

zinozino 2022. 12. 8. 12:30

 

오늘은  어떤 작업을 기다릴 때 사용할 수 있는  인디케이터를 만들어 보겠습니다.  

 

프레임워크에서 제공하는 것을 사용할 수도 있지만 커스텀해서 사용하는 경우가 많기 때문에 

간단히 만들 수 있는 UI를 소개할까 합니다.

@MainActor class UIActivityIndicatorView : UIView

 

 

 

인디케이터가 돌아가는 것을 볼 수 있게 원의 한 곳이  뚫린 UI를 만들 겁니다.

 

그려지는 UI는 같지만 방법은 두 가지로 설명드릴게요!

 

1) Path로 Shape를 만드는 방법

 

Shape는 View의 프로토콜은 따르는 타입입니다.  또한 (CGRect) -> Path를  구현해줘야 합니다. 

struct CirclePath: Shape { 

	func path(in rect: CGRect) -> Path {
    //rect가 주어지고 Path를 만들어서 반환하세요!
    }
}

 

 

struct CirclePath: Shape {
    func path(in rect: CGRect) -> Path {
     let path = Path()
     
      path.addArc(center: // 1)
                    CGPoint(x: rect.midX, y: rect.midY),
                    radius: rect.width/2,
                    startAngle: Angle.degrees(0),
                    endAngle: Angle(degrees: 320),
                    clockwise: false
        )
   	 return path
    }
 }

 

1) 원을 곡선으로 이뤄져 있기 때문에  addArc 메서드를 사용했습니다. 

 

center: 이 도형의 중앙은  주어진 rect의 중간값으로 하였습니다.

 

radious: 중앙값으로부터 반지름이 얼마나 되냐?라는 것에 저는  rect 너비 값의 반을 주었습니다.

 

startAngle, endAngle:  0도부터 시계방향으로 320을 주면 40도가 빠진 곡선을 그리게 됩니다.

 

clockwise: 각도의 방향인데요.

true로 하면 시계 반대방향으로 각도 방향이 됩니다. 하여 저는 false로 하여  시계방향으로 각도 방향을 설정하였습니다.

 

 

 

 

회전하는 애니메이션을 만들겠습니다.

 

struct CircleIndicator: View {
   @State var isRotationCircle: Bool = false
    var body: some View {
        VStack {
            Text("Path Drawing indicator")
                .onTapGesture {
                    isRotationCircle.toggle()
                }
            
            CirclePath()
                .stroke(Color.indigo,
                        style: StrokeStyle(lineWidth: 3,
                                           lineCap: .round)
                )
                .frame(width: 50, height: 50)
                .rotationEffect(Angle(degrees: isRotationCircle ? 360 : 0))
                .animation(.linear(duration: 0.5).repeatForever(autoreverses: false),value: isRotationCircle)
        }
    }
}

 

끝점이 뚫려있기 때문에. easeIn 같은 가변적인 애니메이션은 끊길 수 있습니다.

항상 같은 애니메이션인 linear로 해주세요!

 

 

 

2. 그냥 Circle을 쓰면 되잖아?

 

Circle()
	.trim(from: 0.0, to: 320 / 360)
	.stroke(Color.indigo,
            style: StrokeStyle(lineWidth: 3,
                               lineCap: .round)
     )
     .frame(width: 50, height: 50)
     .rotationEffect(Angle(degrees: isRotationCircle ? 360 : 0))
     .animation(.linear(duration: 0.5).
     			repeatForever(autoreverses: false),
                value: isRotationCircle
      )

 

네.. 사실  Shape에 Path를 정의할 필요도 없습니다. trim이라는 메서드를 사용하여  0.0부터 320/ 360( 0.888888)까지 무시하라고 하면  똑같이 그려지고 애니메이션도 똑같이 작동합니다.

 

 

오늘은  원모양의 인디케이터를 만드는 두 가지 방법을 알아봤습니다. 읽으면서

"2번째 방법이 더 간단한데 굳이 Path를 그리는 것까지 알아야 할까?

라고 생각하실 수 있는데요.

 

SwiftUI는 뷰를 그리는 것이  개발자 친화적으로 잘되어있다고 생각하고 있기 때문에

Path를 그릴 줄 알면 나중에 좀 더 복잡하거나 디자이너분이 원하시는 UI/UX를 구현하는데

더 도움이 될 것이라고 생각해서 첫 번째 방법도 적어봤습니다.