[Translation] SwiftUI official tutorial (six)

Please complete Chinese tutorial and see github.com/WillieWangW...

View animation and transitions

Use SwiftUIwhen, as a matter of where we can add animation for the view alone, or to view the status of animate. SwiftUIFor us to deal with all the combinations of animation, overlapping and interrupting complexity.

In this article, we will animate the view that contains a chart to track users use Landmarkswhen behavior app. We'll see by using the animation(_:)animate method to view how simple yes.

Download the project file and follow these steps, you can also open the completed project themselves through the code.

  • Estimated Completion Time: 20 minutes
  • Project File: Download

1. Single View to add animation

When we use on a view animation(_:)when the method SwiftUIdynamically modify this view can be animated properties. A view of the color, transparency, rotation, size, and other attributes are available animation.

1.1 HikeView.swift, open the live preview to test the show and hide charts.

Ensure that the procedures in this article are open live preview, so you can test the results of each step.

1.2 Add animation(.basic())method to open the rotation animation buttons.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    self.showDetail.toggle()
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .padding()
                        .animation(.basic())
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

1.3 Add a button to make larger animation when the chart display.

animation(_:) It will act in view of the packaging of all the animation changes.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    self.showDetail.toggle()
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                        .animation(.basic())
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

1.4 animation type from the .basic()change .spring().

SwiftUIComprising with preset or custom easing basic animation, and an elastic and fluid animation. We can adjust the speed of the animation, set the delay before the animation begins, or specify the animation repeats.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    self.showDetail.toggle()
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                        .animation(.spring())
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

Try to scaleEffectadd another animation methods above method to close the rotation animation.

Around SwiftUItry to combine different animation effects to see which effects are.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    self.showDetail.toggle()
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .animation(nil)
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                        .animation(.spring())
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

1.6 before proceeding with the next section, delete the two animation(_:)methods.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    self.showDetail.toggle()
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))

                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()

                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

2. The change of state of animation

Now if we have learned to add animation to a single view, it is time to change the status of the added value of the animation.

In this section, we will give the user clicks the button and switch showDetailoccurs when the state attribute all changes add animation.

2.1 showDetail.toggle()calls package to withAnimationfunction.

By the showDetailopen button and properties affect the HikeDetailview now has an animated transitions.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    withAnimation {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

Slow down the animation to see SwiftUIan animation of how you can interrupt.

To 2.2 withAnimationThe method of transmitting a base animation 4 seconds.

We can deliver the same type of animation to animation(_:)the withAnimationfunction.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    withAnimation(.basic(duration: 4)) {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

2.3 try to open and close the chart view during the animation.

2.4 Before entering the next section, from the withAnimationremoval of slow animation function.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    withAnimation {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
            }
        }
    }
}
复制代码

3. Customize View transitions

By default, view through the fade in and fade transition to the screen and the outer screen. We can use transition(_:)methods to customize transitions.

3.1 is satisfied condition display to HikeViewadd a transition(_:)method.

Now slide the icon will appear and disappear.

HikeView.swift

import SwiftUI

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    withAnimation {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
                    .transition(.slide)
            }
        }
    }
}
复制代码

3.2 The transition to extract AnyTransitionstatic properties.

This can keep the code clear when you expand a custom transition. For custom transition, we can use SwiftUIthe same .reference numerals.

HikeView.swift

import SwiftUI

extension AnyTransition {
    static var moveAndFade: AnyTransition {
        AnyTransition.slide
    }
}

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    withAnimation {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
                    .transition(.moveAndFade)
            }
        }
    }
}
复制代码

3.3 replaced the use of move(edge:)transitions, so the chart will slide in and out from the same side.

HikeView.swift

import SwiftUI

extension AnyTransition {
    static var moveAndFade: AnyTransition {
        AnyTransition.move(edge: .trailing)
    }
}

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    withAnimation {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
                    .transition(.moveAndFade)
            }
        }
    }
}
复制代码

3.4 using the asymmetric(insertion:removal:)method to display to view and disappears provide different transitions.

HikeView.swift

import SwiftUI

extension AnyTransition {
    static var moveAndFade: AnyTransition {
        let insertion = AnyTransition.move(edge: .trailing)
            .combined(with: .opacity)
        let removal = AnyTransition.scale()
            .combined(with: .opacity)
        return .asymmetric(insertion: insertion, removal: removal)
    }
}

struct HikeView: View {
    var hike: Hike
    @State private var showDetail = false

    var body: some View {
        VStack {
            HStack {
                HikeGraph(data: hike.observations, path: \.elevation)
                    .frame(width: 50, height: 30)

                VStack(alignment: .leading) {
                    Text(hike.name)
                        .font(.headline)
                    Text(hike.distanceText)
                }

                Spacer()

                Button(action: {
                    withAnimation {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                }
            }

            if showDetail {
                HikeDetail(hike: hike)
                    .transition(.moveAndFade)
            }
        }
    }
}
复制代码

4. The combination of complex effects to animation

When you click the button below the strip, the graph switching between three different sets of data. In this section, we will use a combination of animation graphics composed of Capsuledynamic, fluctuating transition.

4.1 showDetaildefaults changed true, and the HikeViewpreview is fixed canvas, the

This allows us to still be able to see the chart in the context of the production of animation in other documents.

4.2 GraphCapsule.swift, add a new computing animation attributes, and apply Capsulethe shape.

GraphCapsule.swift

import SwiftUI

struct GraphCapsule: View {
    var index: Int
    var height: Length
    var range: Range<Double>
    var overallRange: Range<Double>

    var heightRatio: Length {
        max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
    }

    var offsetRatio: Length {
        Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
    }

    var animation: Animation {
        Animation.default
    }

    var body: some View {
        Capsule()
            .fill(Color.gray)
            .frame(height: height * heightRatio, alignment: .bottom)
            .offset(x: 0, y: height * -offsetRatio)
            .animation(animation)
        )
    }
}
复制代码

4.3 The animation was changed elastic animation, using a bar graph so that the initial speed jump.

GraphCapsule.swift

import SwiftUI

struct GraphCapsule: View {
    var index: Int
    var height: Length
    var range: Range<Double>
    var overallRange: Range<Double>

    var heightRatio: Length {
        max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
    }

    var offsetRatio: Length {
        Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
    }

    var animation: Animation {
        Animation.spring(initialVelocity: 5)
    }

    var body: some View {
        Capsule()
            .fill(Color.gray)
            .frame(height: height * heightRatio, alignment: .bottom)
            .offset(x: 0, y: height * -offsetRatio)
            .animation(animation)
        )
    }
}
复制代码

4.4 speed up the animation speed, shorten the time required to move to the new position of each section.

GraphCapsule.swift

import SwiftUI

struct GraphCapsule: View {
    var index: Int
    var height: Length
    var range: Range<Double>
    var overallRange: Range<Double>

    var heightRatio: Length {
        max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
    }

    var offsetRatio: Length {
        Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
    }

    var animation: Animation {
        Animation.spring(initialVelocity: 5)
            .speed(2)
    }

    var body: some View {
        Capsule()
            .fill(Color.gray)
            .frame(height: height * heightRatio, alignment: .bottom)
            .offset(x: 0, y: height * -offsetRatio)
            .animation(animation)
        )
    }
}
复制代码

4.5 The Capsuleposition on the chart for each animation to add delay.

GraphCapsule.swift

import SwiftUI

struct GraphCapsule: View {
    var index: Int
    var height: Length
    var range: Range<Double>
    var overallRange: Range<Double>

    var heightRatio: Length {
        max(Length(magnitude(of: range) / magnitude(of: overallRange)), 0.15)
    }

    var offsetRatio: Length {
        Length((range.lowerBound - overallRange.lowerBound) / magnitude(of: overallRange))
    }

    var animation: Animation {
        Animation.spring(initialVelocity: 5)
            .speed(2)
            .delay(0.03 * Double(index))
    }

    var body: some View {
        Capsule()
            .fill(Color.gray)
            .frame(height: height * heightRatio, alignment: .bottom)
            .offset(x: 0, y: height * -offsetRatio)
            .animation(animation)
        )
    }
}
复制代码

4.6 observe the custom animation between the chart when transition is how to create a ripple effect.

Reproduced in: https: //juejin.im/post/5cfbc5356fb9a07ee1691b10

Guess you like

Origin blog.csdn.net/weixin_34281477/article/details/91460737