SwiftUI 制作一个幸运大转盘抽奖效果

年底各种活动,今天也是刚参与了一次幸运大转盘抽奖,可惜手气不佳,于是使用 SwiftUI 也来制作一个转盘抽奖示例


演示效果

SwiftUI 幸运大转盘抽奖效果演示

关键代码示例

//
//  Created by codeun.com on 25/10/24.
//

import SwiftUI
import Combine

// 用于管理轮盘的状态和行为
class RouletteViewModel: ObservableObject {
    
    // @Published属性:当这些属性改变时,UI会自动刷新
    @Published var segmentCount = 1 // 当前轮盘分段的数量
    @Published var rotation: Double = 0 // 当前旋转角度,用于动画效果
    @Published var isSpinning = false // 是否正在旋转
    @Published var winningName: String = "" // 中奖项的名称
    @Published var showAlert = false // 是否显示中奖提示
    @Published var usedColors: [Color] = [.blue] // 已经使用过的颜色
    @Published var colors: [Color] = [.black.opacity(0.35)] // 轮盘颜色数组
    @Published var usedColorsNames: [Color] = [.blue] // 已使用的颜色名称数组
    @Published var names: [String] = [""] // 存储每个分段的名称
    @Published var winningColor: [String] = [] // 存储中奖分段的颜色
    @Published var newColorName: String = "" // 新增分段的颜色名称
    
    // 非Published属性:不会自动刷新UI
    var selectedColor: Color = .blue // 当前选中的颜色
    var lastUsedColor: Color = .clear // 上一个使用的颜色
    let availableColors: [Color] = [.red.opacity(0.85), .blue, .green, .yellow, .purple, .orange, .brown, .cyan, .teal, .indigo] // 可用的颜色集合
    let totalSpinDuration: Double = 5.0 // 旋转总持续时间
    var totalRotations: Double = 3500 // 总旋转角度,模拟多圈转动
    
    // 轮盘旋转方法
    func spinRoulette() {
        // 确保不在旋转中时才执行旋转逻辑
        guard !isSpinning else { return }
        isSpinning = true
        
        // 使用withAnimation对旋转进行动画效果
        withAnimation(Animation.timingCurve(0.1, 0.8, 0.3, 1.0, duration: totalSpinDuration)) {
            rotation += totalRotations // 增加旋转角度,触发旋转动画
        }
        
        // 旋转结束后执行的逻辑
        DispatchQueue.main.asyncAfter(deadline: .now() + totalSpinDuration) {[weak self] in
            guard let this = self else { return }
            this.isSpinning = false // 旋转完成,重置状态
            
            // 计算当前旋转后的角度并确定中奖项
            let incompleteRotation = Int(this.rotation) % 360
            let restOfRotation: Double = Double(incompleteRotation) / (360.0 / Double(this.segmentCount))
            let restOfRotationInteger = Int(restOfRotation)
            let winningIndex = Double(restOfRotationInteger) == restOfRotation ? restOfRotationInteger : restOfRotationInteger + 1
            
            // 确定中奖分段的颜色及名称
            this.winningColor = this.names.reversed()
            this.winningName = this.winningColor[winningIndex - 1]
            this.showAlert = true // 显示中奖提示
        }
    }
    
    // 添加新分段方法
    func addNewItem() {
        // 确保新分段的颜色名称不为空
        guard !newColorName.isEmpty else { return }
        addNewColorAndName(name: newColorName) // 添加新颜色和名称
        names.removeAll(where: { $0 == "" }) // 移除空项
        segmentCount = names.count // 更新分段数量
        newColorName = "" // 清空新颜色名称
    }
    
    // 删除分段方法
    func deleteItems(at offsets: IndexSet) {
        names.remove(atOffsets: offsets) // 从名称数组中移除指定分段
        segmentCount -= 1 // 更新分段数量
        if names.isEmpty { // 若无剩余分段,则初始化为空项
            names = [""]
            segmentCount = 1
        }
    }
    
    // 添加新颜色和名称方法
    func addNewColorAndName(name: String) {
        // 检查是否有可用的颜色未使用
        if usedColors.count < availableColors.count {
            let unusedColors = availableColors.filter { !usedColors.contains($0) }
            if let randomColor = unusedColors.randomElement() { // 随机选择一个未使用颜色
                colors.insert(randomColor, at: 0)
                usedColors.append(randomColor)
                lastUsedColor = randomColor // 更新最后使用的颜色
                if availableColors.firstIndex(of: randomColor) != nil {
                    names.append(name) // 添加新名称到分段
                }
            }
        } else {
            // 若所有颜色已使用,从已使用颜色中随机选择一个新颜色
            if let randomColor = availableColors.filter({ $0 != lastUsedColor && $0 != colors[0] }).randomElement() {
                colors.append(randomColor)
                lastUsedColor = randomColor // 更新最后使用的颜色
                if availableColors.firstIndex(of: randomColor) != nil {
                    names.append(name) // 添加新名称到分段
                }
            }
        }
    }
    
}


完整代码下载

SwiftUI 制作一个幸运大转盘抽奖效果

SwiftUI 幸运大转盘抽奖效果Demo

赞助会员赞助会员免费
资源价格 ¥5.00 销售数量 0 更新时间 2024-10-26
已付费?登录刷新

  本文自 https://www.codeun.com 发布,相应代码均自主编写并严格审阅和测试,完整代码中包含丰富的学习笔记和使用方式、实用技巧。
  · 如若转载,请注明出处:https://www.codeun.com/archives/1361.html ·

(0)
上一篇 2024-10-24 下午5:45
下一篇 2024-10-26

发表回复

登录后才能评论