iOS

[Gradient Animation] AngularGradient Border 애니메이션 넣기

Dev.YoungKyu 2022. 9. 25. 19:12

1. 이미지 리사이징

struct ContentView: View {
    var body: some View {
        Image("IU")
            .resizable()
            .scaledToFit()
            .frame(width: 300)
            .mask { RoundedRectangle(cornerRadius: 12) }
    }
}

이미지에 코너곡선만 줬을때

 

2. 그림자 추가

struct ContentView: View {
    var body: some View {
        Image("IU")
            .resizable()
            .scaledToFit()
            .frame(width: 300)
            .mask { RoundedRectangle(cornerRadius: 12) }
            .shadow(radius: 8)
    }
}

그림자 효과 추가

 

3. AngularGradient Border 추가

struct ContentView: View {
    private let gradientColors: [Color] = [.red, .yellow, .green, .blue, .purple, .red]
    var body: some View {
        Image("IU")
            .resizable()
            .scaledToFit()
            .frame(width: 300)
            .mask { RoundedRectangle(cornerRadius: 12) }
            .shadow(radius: 8)
            .overlay {
                gradientBorderView
            }
    }
    var gradientBorderView: some View {
        RoundedRectangle(cornerRadius: 12)
            .strokeBorder(
                AngularGradient(gradient: Gradient(colors: gradientColors), center: .center))
    }
}

테두리가 알록달록

 

4. AngularGradient에 Animation 추가

struct ContentView: View {
	// Color를 너무 적게 넣거나하면 동작을 안할때가 있더라구요ㅠ 아직은 원인불명..
    private let gradientColors: [Color] = [.red, .yellow, .green, .blue, .purple, .red]
    @State  var gradientAngle: Double = 0 
    var body: some View {
        Image("IU")
            .resizable()
            .scaledToFit()
            .frame(width: 300)
            .mask { RoundedRectangle(cornerRadius: 12) }
            .shadow(radius: 8)
            .overlay {
                gradientBorderView
            }
    }
    var gradientBorderView: some View {
        RoundedRectangle(cornerRadius: 12)
            .strokeBorder(
            	// gradientAngle이 WithAnimaion으로 변경되면서 변화에 따라 AngularGradient를 회전
                AngularGradient(gradient: Gradient(colors: gradientColors), 
                				center: .center, 
                				angle: .degrees(gradientAngle)))
            .onAppear {
            	// duration을 너무 짧거나 길게 바꾸면 동작을 안할때가 있더라구요ㅠ 
                // 성능관련 문제같은데 정확한 원인은 모르겠네요!
                withAnimation(.linear(duration: 3).repeatForever(autoreverses: false)) {
                    self.gradientAngle = 360
                }
            }
    }
}

 

빙글빙글 돌아가니 예쁘네요

 

확대샷




gradientAngle 까지는 잘 접근했는데 컬러 설정애니메이션 길이 설정(duration)에 따라서 애니메이션이 동작 안할 때가 많아 애먹었습니다ㅜㅜ 확실하게 언제 되고 언제 안되는지 정리하고 싶었는데 아쉽네요 이유에 대해서 아시는 분은 댓글로 알려주시면 감사하겠습니다!

 

애니메이션 미동작 원인 및 해결방법

some View 로 구현했던게 원인이었던 것 같습니다!

rootView의@State 변수 하나로 다수의 some View의 애니메이션을 컨트롤하려고 해 문제가 된 것 같습니다.

 

struct ContentView: View {
    var body: some View {
        Image("IU")
            .resizable()
            .scaledToFit()
            .frame(width: 300)
            .mask { RoundedRectangle(cornerRadius: 12) }
            .shadow(radius: 8)
            .overlay {
                GradientBorderView()
            }
    }
}

struct GradientBorderView: View {
    private var colors: [Color] = [.red, .yellow, .green, .blue, .purple, .red]
    @State var gradientAngle: Double = 0
    var body: some View {
        RoundedRectangle(cornerRadius: 8)
            .strokeBorder(
                AngularGradient(gradient: Gradient(colors: colors), center: .center, angle: .degrees(gradientAngle)))
            .onAppear {
                withAnimation(.linear(duration: 3).repeatForever(autoreverses: false)) {
                    gradientAngle = 360
                }
            }
    }
}

UI는 메인스레드에서 동작하는데 애니메이션도 UI니까 메인스레드에서 애니메이션을 동작하게 하는 과정에서 문제가 있지 않았을까 싶습니다. 더 자세한 원인이나 틀린 부분이 있다면 댓글로 알려주시면 감사하겠습니다!