【SwiftUI模块】0017、SwiftUI搭建一个类似喝水App的喝水进度动画效果

SwiftUI模块系列 - 已更新17篇
SwiftUI项目 - 已更新1个项目
往期Demo源码下载

技术:SwiftUI、SwiftUI3.0、喝水进度、喝水App、喝水进度动画
运行环境:
SwiftUI3.0 + Xcode13.4.1 + MacOS12.5 + iPhone Simulator iPhone 13 Pro Max

概述

SwiftUI搭建一个类似喝水App的喝水进度动画效果

详细

一、运行效果

请添加图片描述

二、项目结构图

在这里插入图片描述

三、程序实现 - 过程

思路:

  1. 先搭建头部的基本信息
  2. 通过加载水滴的系统图片
  3. 画路径 - 通过正弦公式 画出一个水纹的弧度
    在这里插入图片描述
    画出下面的效果
    请添加图片描述
  4. 通过mask 进行遮盖超出范围 - 使用给定视图的 Alpha 通道屏蔽此视图。
  5. 通过动画 并且每个两秒重复动画 达到类似 日常生活中的水遇到风的水纹波动效果
  6. 画几个小透明点 - 类似水的气泡
  7. 通过添加按钮 控制水滴的进度

1.创建一个项目命名为 WaterWave

在这里插入图片描述
在这里插入图片描述

1.1.引入资源文件和颜色

颜色
BG #F1F3F9
Green #4747EB
图片1张

在这里插入图片描述

2. 创建一个虚拟文件New Group 命名为 View

在这里插入图片描述
在这里插入图片描述

4. 创建一个文件New File 选择SwiftUI View类型 命名为Home

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Code

ContentView - 主窗口

主要是展示主窗口Home

//
//  ContentView.swift
//  Shared
//
//  Created by lyh on 2022/8/29.
//

import SwiftUI

struct ContentView: View {
    
    
    var body: some View {
    
    
       Home()
    }
}

struct ContentView_Previews: PreviewProvider {
    
    
    static var previews: some View {
    
    
        ContentView()
    }
}

Home - 主页

思路

  1. 先搭建头部的基本信息
  2. 通过加载水滴的系统图片
  3. 画路径 - 通过正弦公式 画出一个水纹的弧度
    在这里插入图片描述
    画出下面的效果
    请添加图片描述
  4. 通过mask 进行遮盖超出范围 - 使用给定视图的 Alpha 通道屏蔽此视图。
  5. 通过动画 并且每个两秒重复动画 达到类似 日常生活中的水遇到风的水纹波动效果
  6. 画几个小透明点 - 类似水的气泡
  7. 通过添加按钮 控制水滴的进度
//
//  Home.swift
//  WaterWave (iOS)
//
//  Created by lyh on 2022/8/29.
//

import SwiftUI

struct Home: View {
    
    
    
    @State var progress : CGFloat = 0.5
    @State var startAnimation: CGFloat = 0
    
    var body: some View {
    
    
        VStack{
    
    
            Image("Pic")
                .resizable()
                .aspectRatio(contentMode:.fill)
                .frame(width: 100, height: 100)
                .clipShape(Circle())
                .padding(10)
                .background(.white,in:Circle())
            
            Text("宇夜iOS")
                .fontWeight(.semibold)
                .foregroundColor(.gray)
                .padding(.bottom,30)
            
            // MARK : Ware Form
            GeometryReader{
    
    proxy in
                let size = proxy.size
                
                ZStack{
    
    
                    // MARK:Water Drop
                    // 水滴
                    Image(systemName: "drop.fill")
                        .resizable()
                        .renderingMode(.template)
                        .aspectRatio(contentMode: .fit)
                        .foregroundColor(.white)
                    // Streching in X Axis
                    // X轴拉伸
                        .scaleEffect(x:1.1,y:1)
                        .offset(y:-1)
                    
                    // Wave Form Shape
                    // 波形的形状
                    WaterWave(progress: progress, waveHeight: 0.1, offset: startAnimation)
                        .fill(Color("Blue"))
                    // Water Drops
                    // 水滴
                        .overlay(content: {
    
    
                            ZStack{
    
    
                                Circle()
                                    .fill(.white.opacity(0.1))
                                    .frame(width: 15, height: 15)
                                    .offset(x:-20)
                                
                                Circle()
                                    .fill(.white.opacity(0.1))
                                    .frame(width: 15, height: 15)
                                    .offset(x:40,y:30)
                                
                                Circle()
                                    .fill(.white.opacity(0.1))
                                    .frame(width: 25, height: 25)
                                    .offset(x:-30,y:80)
                                
                                Circle()
                                    .fill(.white.opacity(0.1))
                                    .frame(width: 25, height: 25)
                                    .offset(x:50,y:70)
                                
                                Circle()
                                    .fill(.white.opacity(0.1))
                                    .frame(width: 10, height: 10)
                                    .offset(x:40,y:100)
                                
                                
                                Circle()
                                    .fill(.white.opacity(0.1))
                                    .frame(width: 10, height: 10)
                                    .offset(x:-40,y:50)

                            }
                        })
                    
                    // Masking into Drop Shape
                    // 掩蔽成水滴形状
                        .mask{
    
    
                            Image(systemName: "drop.fill")
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .padding(20)

                        }
                    // Add Button
                        .overlay(alignment: .bottom) {
    
    
                            Button{
    
    
                                progress += 0.01
                            }label: {
    
    
                                Image(systemName: "plus")
                                    .font(.system(size: 40,weight:.black))
                                    .foregroundColor((Color("Blue")))
                                    .shadow(radius: 2)
                                    .padding(25)
                                    .background(.white,in : Circle())
                            }
                            .offset(y:40)
                        }
                }
                .frame(width: size.width, height: size.height, alignment: .center)
                .onAppear{
    
    
                    // Lopping Animation
                    // 每隔2秒进行动画
                    withAnimation(.linear(duration: 2).repeatForever(autoreverses: false)){
    
    
                        startAnimation = size.width
                    }
                }
            
            }
            .frame(height:350)
            .padding(.bottom,50)
            // 测试
            // Slider(value: $progress)
        }
        .padding()
        .frame(maxWidth:.infinity,maxHeight: .infinity,alignment: .top)
        .background(Color("BG"))
    }
}

struct Home_Previews: PreviewProvider {
    
    
    static var previews: some View {
    
    
        ContentView()
    }
}

// Shape形状
struct WaterWave: Shape {
    
    
    
    var progress : CGFloat
    
    // Wave Height
    var waveHeight : CGFloat
    
    // Intial Aniamtion Start
    var offset : CGFloat
    
    // Enabling Aniamtion
    var animatableData: CGFloat{
    
    
        get {
    
    offset}
        set {
    
    offset = newValue}
    }
    
    func path(in rect: CGRect) -> Path {
    
    
        return Path{
    
    path in
            path.move(to:.zero)
            // MARK: Drawing Waves using Sine
            // 用正弦画波浪
            let progressHeight: CGFloat = (1 - progress) * rect.height
            let height = waveHeight * rect.height
            
            for value in stride(from: 0, to: rect.width, by: 2){
    
    
                let x : CGFloat = value
                let sine : CGFloat = sin(Angle(degrees:  value + offset).radians)
                let y : CGFloat = progressHeight + (height * sine)
                
                path.addLine(to: CGPoint(x: x, y: y))
                
                // Bottom Portion
                path.addLine(to: CGPoint(x: rect.width, y: rect.height))
                path.addLine(to: CGPoint(x: 0, y: rect.height))
                
            }
            
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42816425/article/details/126576192