import SwiftUI
struct Demo01: View {
@State private var enable = false
var body: some View {
demo01
// demo02
// demo03
// demo04
// demo05
// demo06
// demo07
}
var demo01 : some View{
VStack(alignment: .center, spacing: 0) {
// Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
// .font(.title)
// .padding()
// Text("Animation")
// .font(.title2)
// .foregroundColor(.red)
// .fontWeight(.bold)
// .scaleEffect(enable ? 3.0 : 1.0)
// .animation(.default.repeatForever())//repeatForever永远重复
// .padding()
Image(systemName: "heart.fill")
.foregroundColor(.red)
.font(.largeTitle)
.scaleEffect(enable ? 5.0 : 1.0)
.animation(
.timingCurve(0.76, 0, 0.24, 1,duration: 1)
.repeatForever()
)
}
.onAppear {
enable = true
}
}
//隐式声明动画
var demo02 : some View{
VStack(spacing: 50){
RoundedRectangle(cornerRadius: enable ? 200 : 0)
// .fill(enable ? .red : .green)
// .opacity(enable ? 1.0 : 0.3)//透明度
// .animation(.default)
// .animation(.linear)
// .animation(.easeIn)
// .animation(.easeOut)
// .animation(.easeInOut)
// .animation(.spring())
// .animation(.timingCurve(0.87, 0, 0.13, 1,duration: 1))//时间曲线 easings.net
// .animation(.interactiveSpring())
.animation(.interpolatingSpring(mass: 0.7, stiffness: 200, damping: 5, initialVelocity: 4))//弹性动画 kiteapp.co
.frame(width: 300, height: 300, alignment: .center)
Button {
enable.toggle()
} label: {
Text("执行动画")
}
}
}
//显式声明动画
@State private var state1 = false
@State private var state2 = false
@State private var state3 = false
var demo03 : some View {
VStack(spacing: 50){
RoundedRectangle(cornerRadius: state1 ? 200 : 0)
.fill(state2 ? .red : .green)
.opacity(state3 ? 1.0 : 0.3)//透明度
.frame(width: 300, height: 300, alignment: .center)
Button {
//显示的声明动画
withAnimation (.linear) {
state3.toggle()
}
state2.toggle()
state1.toggle()
} label: {
Text("执行动画")
}
}
}
var demo04 : some View {
VStack(spacing: 50){
RoundedRectangle(cornerRadius: enable ? 200 : 0)
.fill(enable ? .red : .green)
.opacity(enable ? 1.0 : 0.3)//透明度
.animation(
.linear
// .delay(5)//延迟5秒执行动画
// .repeatCount(7)//动画执行次数
.repeatForever()//永远重复执行
// .repeatForever(autoreverses: false)//不返回执行
.speed(3)//动画执行速度
)
.frame(width: 300, height: 300, alignment: .center)
Button {
enable.toggle()
} label: {
Text("执行动画")
}
}
}
@State private var isShow = true
var demo05 : some View{
Form{
HStack {
if isShow{
Text("标题1")
}
Spacer()
Toggle(isOn: $isShow) {
Text("")
}
.onChange(of: isShow) { newValue in
withAnimation {
isShow.toggle()
}
}
.labelsHidden()
}
HStack {
if isShow{
Text("标题2")
}
Spacer()
Toggle(isOn: $isShow.animation(.linear)) {
Text("")
}
.labelsHidden()
}
}
}
@State private var state4 = false
var width : CGFloat {
state4 ? 100 : 50
}
var demo06 : some View {
VStack(spacing : 50) {
HStack {
Text("color")
Spacer()
Rectangle()
.fill(state4 ? .red : .green)
.frame(width: 100, height: 100)
}
HStack {
Text("size")
Spacer()
Rectangle()
.fill(.purple)
.frame(width: width, height: width)
Rectangle()
.fill(.yellow)
.frame(width: 100, height: 100)
.scaleEffect(state4 ? 1 : 0.5)
}
HStack {
Text("opacity")
Spacer()
Rectangle()
.fill(.blue)
.frame(width: 100, height: 100)
.opacity(state4 ? 1.0 : 0)
}
HStack {
Text("border")
Spacer()
Rectangle()
.fill(.orange)
.frame(width: 100, height: 100, alignment: .center)
.border(.green,width: state4 ? 10 : 2)
Circle()
.fill(.orange)
.frame(width: 100, height: 100, alignment: .center)
.overlay(
Circle()
.strokeBorder(.blue,lineWidth: state4 ? 10 : 2)
)
}
HStack {
Text("opacity")
Spacer()
Rectangle()
.fill(.blue)
.frame(width: 100, height: 100)
.cornerRadius(state4 ? 30 : 0)
}
HStack {
Text("opacity")
Spacer()
Rectangle()
.fill(.red)
.frame(width: 100, height: 100)
.rotationEffect(.degrees(state4 ? 360 : 0))
}
}
.animation(.linear(duration: 2).repeatForever())
.padding()
.font(.title)
.onAppear {
state4 = true
}
}
let letters = Array("阿巴阿巴阿巴阿巴阿巴")
@State private var dragPosition : CGSize = .zero
var demo07 : some View {
HStack {
ForEach(0..<letters.count){
Text(String(letters[$0]))
.padding(5)
.font(.title)
.textCase(.uppercase)
.background(state4 ? Color.blue : Color.red)
.offset(dragPosition)
.animation(.linear.delay(Double($0)/20))
}
}
.gesture(
DragGesture()
.onChanged({ po in
self.dragPosition = po.translation
})
.onEnded({ _ in
self.dragPosition = .zero
self.state4.toggle()
})
// .onChanged{
// self.dragPosition = $0.translation
// }
// .onEnded{_ in
// self.dragPosition = .zero
// self.state4.toggle()
// }
)
}
}
struct Demo02: View {
var body: some View {
// demo01//水波纹开始按钮
// demo02//点赞红心效果
// demo03//圆圈加载loading
// demo04//圆形进度条
// demo05//条形进度条
// demo06//跑马灯
// demo07//Transition通过combined组合动画(preview效果不如模拟器效果好)
demo08//Transition自定义扩展动画
}
@State private var state1 = false
var demo01 : some View {
Button("开始") {
state1 = true
}
.padding(50)
.background(Color.red)
.foregroundColor(Color.white)
.clipShape(Circle())
.overlay(
Circle()
.stroke(Color.red)
.scaleEffect(state1 ? 2.0 : 1.0)
.opacity(state1 ? 0 : 1)
.animation(.easeInOut(duration: 1).repeatForever(autoreverses: false))
)
}
var demo02 : some View {
Image(systemName: "heart.fill")
.font(.title)
.foregroundColor(.red)
.scaleEffect(state1 ? 3 : 1)
.opacity(state1 ? 1 : 0.2)
.animation(.interpolatingSpring(mass: 0.7, stiffness: 200, damping: 10, initialVelocity: 4).repeatForever(autoreverses: false))
.onAppear {
state1 = true
}
}
let strokestyle = StrokeStyle(lineWidth:2,lineCap: .round)
var demo03 : some View {
VStack{
// ProgressView()
demo03_1
}
.frame(width: 30, height: 30, alignment: .center)
.padding()
.background(Color.white)
.shadow(radius: 3.0)
}
var demo03_1 : some View {
VStack{
Circle()
.trim(from: 0.0, to: 0.7)
.stroke(
AngularGradient(gradient: Gradient(colors: [Color.gray,Color.gray.opacity(0.5)]), center: .center),style: strokestyle)
.rotationEffect(.degrees(state1 ? 360.0 : 0.0))
.animation(.linear(duration: 0.7).repeatForever(autoreverses: false))
.onAppear {
state1.toggle()
}
}
}
let timer = Timer.publish(every: 1, on: RunLoop.main, in: .common).autoconnect()
@State private var progress : CGFloat = 0
var demo04 : some View{
ZStack {
Circle()
.stroke(Color.gray.opacity(0.3),style: strokestyle)
Circle()
.trim(from: 0.0, to: self.progress)
.stroke(Color.gray,style: strokestyle)
.animation(.default)
.rotationEffect(.degrees(-90))
.onReceive(timer) { _ in
self.progress += 0.1
if self.progress > 1 {
self.progress = 0
}
}
}
.frame(width: 30, height: 30, alignment: .center)
.padding()
.background(Color.white)
.shadow(radius: 3.0)
}
@State private var barWidth : CGFloat = 300.0
@State private var progressWidth : CGFloat = 0.0
var demo05 : some View {
ZStack {
Capsule()
.stroke(Color.gray)
.frame(width: barWidth, height: 20)
.overlay(
VStack(alignment: .leading) {
Capsule()
.fill(Color.gray)
.frame(width: progressWidth, height: 15, alignment: .leading)
.padding(.horizontal,5)
.animation(.linear)
}
.frame(width: barWidth, height: 20, alignment: .leading)
)
.onReceive(timer) { _ in
self.progressWidth += 5
if self.progressWidth >= barWidth{
self.progressWidth = 0.0
}
}
}
}
@State private var scrollText = false
var demo06 : some View {
Text("好难啊,秃头了,阿巴阿巴阿巴")
.foregroundColor(.red)
.offset(x: scrollText ? 400 : 0)
.animation(.linear(duration: 30).speed(10).repeatForever(autoreverses: false))
// .frame(maxWidth: .infinity, alignment: .leading)
.onAppear {
scrollText.toggle()
}
}
@State private var showText = true
var demo07 : some View {
Button {
withAnimation {
showText.toggle()
}
} label: {
ZStack {
Rectangle()
.fill(Color.clear)
.frame(width: 150, height: 60)
.border(.red,width: 4)
if showText {
Text("按钮")
.font(.largeTitle)
.transition(.move(edge: .top).combined(with: .opacity.combined(with: .scale)))
}
}
}
}
var demo08 : some View {
Button {
withAnimation {
showText.toggle()
}
} label: {
ZStack {
Rectangle()
.fill(Color.clear)
.frame(width: 150, height: 60)
.border(.red,width: 4)
if showText {
Text("按钮")
.font(.largeTitle)
.transition(.moveInScaleOut)
// .transition(.moveWithFade)
}
}
}
}
}
extension AnyTransition {
static var moveWithFade : AnyTransition {
return AnyTransition.move(edge: .top).combined(with: .opacity).combined(with: .scale)
}
}
extension AnyTransition {
static var moveInScaleOut : AnyTransition {
let insertion = AnyTransition.move(edge: .top).combined(with: .opacity)
let removal = AnyTransition.scale.combined(with: .opacity)
return AnyTransition.asymmetric(insertion: insertion, removal: removal)
}
}
struct Demo01_Previews: PreviewProvider {
static var previews: some View {
// Demo01()
Demo02()
}
}