swiftui实现vip card的样式方案

121 阅读7分钟

让claude生成一些样式参考, 让后让它转换为swiftui 代码如下。这个是claude3.7给的方案,html转换到swiftui还原度没那么好,今天出了claude4, 可能效果更好。

11.gif

代码如下:

//
//  JoinVipCard.swift
//  mc skin
//
//  Created by martin on 2025/5/22.
//  Copyright © 2025 edgewise. All rights reserved.
//

import SwiftUI

// MARK: - VIP卡片主组件
struct VIPFeedCard: View {
    let vipType: VIPType
    let username: String
    let timeAgo: String
    let avatarURL: String?
    
    var body: some View {
        VStack(spacing: 0) {
            switch vipType {
            case .flame:
                FlameVIPCard(username: username, timeAgo: timeAgo, avatarURL: avatarURL)
            case .lava:
                LavaVIPCard(username: username, timeAgo: timeAgo, avatarURL: avatarURL)
            case .gold:
                GoldVIPCard(username: username, timeAgo: timeAgo, avatarURL: avatarURL)
            case .rainbow:
                RainbowVIPCard(username: username, timeAgo: timeAgo, avatarURL: avatarURL)
            }
        }
        .background(Color.black.opacity(0.1))
        .cornerRadius(8)
        .padding(.horizontal, 16)
        .padding(.vertical, 8)
    }
}

// MARK: - VIP类型枚举
enum VIPType {
    case flame   // 烈焰VIP
    case lava    // 熔岩VIP
    case gold    // 黄金VIP
    case rainbow // 彩虹VIP
}

// MARK: - 烈焰VIP卡片
struct FlameVIPCard: View {
    let username: String
    let timeAgo: String
    let avatarURL: String?
    
    @State private var glowIntensity: Double = 0.5
    @State private var shimmerOffset: CGFloat = -200
    
    var body: some View {
        ZStack {
            // 主背景渐变
            LinearGradient(
                colors: [
                    Color(red: 1.0, green: 0.55, blue: 0.0),
                    Color(red: 1.0, green: 0.65, blue: 0.0),
                    Color(red: 1.0, green: 0.5, blue: 0.0)
                ],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
            
            // 闪光扫过效果
            LinearGradient(
                colors: [
                    Color.clear,
                    Color.white.opacity(0.3),
                    Color.clear
                ],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
            .offset(x: shimmerOffset)
            .animation(
                Animation.linear(duration: 2)
                    .repeatForever(autoreverses: false),
                value: shimmerOffset
            )
            
            VStack(alignment: .leading, spacing: 12) {
                // 用户信息行
                HStack {
                    // 头像
                    AsyncImage(url: URL(string: avatarURL ?? "")) { image in
                        image
                            .resizable()
                            .interpolation(.none) // 像素风格
                    } placeholder: {
                        Rectangle()
                            .fill(Color.gray.opacity(0.6))
                    }
                    .frame(width: 40, height: 40)
                    .border(Color.gray.opacity(0.8), width: 1)
                    
                    VStack(alignment: .leading, spacing: 2) {
                        HStack {
                            Text(username)
                                .font(.custom("Menlo", size: 10))
                                .foregroundColor(.green)
                            
                            Text("🔥 烈焰VIP")
                                .font(.custom("Menlo", size: 7))
                                .foregroundColor(.white)
                                .padding(.horizontal, 6)
                                .padding(.vertical, 2)
                                .background(Color(red: 1.0, green: 0.27, blue: 0.0))
                                .border(Color(red: 1.0, green: 0.15, blue: 0.0), width: 1)
                        }
                        
                        Text(timeAgo)
                            .font(.custom("Menlo", size: 6))
                            .foregroundColor(.gray)
                    }
                    
                    Spacer()
                }
                
                // 内容文本
                VStack(alignment: .leading, spacing: 6) {
                    Text("🔥 恭喜开通烈焰VIP会员!")
                        .font(.custom("Menlo", size: 9))
                        .fontWeight(.bold)
                        .foregroundColor(.black)
                    
                    VStack(alignment: .leading, spacing: 3) {
                        Text("✨ 解锁全部高级皮肤库")
                        Text("🧡 专属烈焰标识闪耀登场")
                        Text("🚀 优先体验最新功能")
                        Text("🎁 每月赠送专属皮肤礼包")
                    }
                    .font(.custom("Menlo", size: 8))
                    .foregroundColor(.black)
                }
                
                // 统计信息
                HStack(spacing: 15) {
                    Text("🔥 烈焰特权已激活")
                    Text("🌟 等级提升至 LV.MAX")
                }
                .font(.custom("Menlo", size: 7))
                .foregroundColor(.black.opacity(0.8))
            }
            .padding(16)
            
            // 浮动粒子效果
            ForEach(0..<3, id: \.self) { index in
                ParticleView(delay: Double(index))
            }
        }
        .border(Color(red: 1.0, green: 0.4, blue: 0.0), width: 2)
        .shadow(color: Color(red: 1.0, green: 0.55, blue: 0.0).opacity(glowIntensity), radius: 10)
        .onAppear {
            // 启动动画
            withAnimation(Animation.easeInOut(duration: 3).repeatForever()) {
                glowIntensity = 1.0
            }
            withAnimation(Animation.linear(duration: 2).repeatForever(autoreverses: false)) {
                shimmerOffset = 200
            }
        }
    }
}

// MARK: - 熔岩VIP卡片
struct LavaVIPCard: View {
    let username: String
    let timeAgo: String
    let avatarURL: String?
    
    @State private var glowPulse: Double = 0.7
    
    var body: some View {
        ZStack {
            // 熔岩渐变背景
            LinearGradient(
                colors: [
                    Color(red: 0.8, green: 0.33, blue: 0.0),
                    Color(red: 1.0, green: 0.55, blue: 0.0),
                    Color(red: 1.0, green: 0.7, blue: 0.28)
                ],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
            
            VStack(alignment: .leading, spacing: 12) {
                // 用户信息行
                HStack {
                    AsyncImage(url: URL(string: avatarURL ?? "")) { image in
                        image
                            .resizable()
                            .interpolation(.none)
                    } placeholder: {
                        Rectangle().fill(Color.gray.opacity(0.6))
                    }
                    .frame(width: 40, height: 40)
                    .border(Color.gray.opacity(0.8), width: 1)
                    
                    VStack(alignment: .leading, spacing: 2) {
                        Text(username)
                            .font(.custom("Menlo", size: 10))
                            .foregroundColor(.green)
                        
                        Text(timeAgo)
                            .font(.custom("Menlo", size: 6))
                            .foregroundColor(.gray)
                    }
                    
                    Spacer()
                }
                
                // 内容
                VStack(alignment: .leading, spacing: 6) {
                    HStack {
                        Text("🧡")
                            .font(.custom("Menlo", size: 10))
                            .scaleEffect(1.2)
                            .animation(
                                Animation.easeInOut(duration: 1)
                                    .repeatForever(autoreverses: true),
                                value: glowPulse
                            )
                        
                        Text("熔岩之力!开通熔岩VIP会员!")
                            .font(.custom("Menlo", size: 9))
                            .fontWeight(.bold)
                            .foregroundColor(.white)
                    }
                    
                    VStack(alignment: .leading, spacing: 3) {
                        Text("🌋 专属熔岩光环效果")
                        Text("🎭 解锁传奇级皮肤收藏")
                        Text("🧡 加入熔岩VIP专属讨论群")
                        Text("🏆 参与熔岩VIP专属活动资格")
                    }
                    .font(.custom("Menlo", size: 8))
                    .foregroundColor(.white)
                }
                
                // 统计信息
                HStack(spacing: 15) {
                    Text("🌋 999+ 皮肤已解锁")
                    Text("🔥 熔岩圈子邀请中")
                }
                .font(.custom("Menlo", size: 7))
                .foregroundColor(.white.opacity(0.9))
            }
            .padding(16)
        }
        .border(Color(red: 1.0, green: 0.4, blue: 0.0), width: 2)
        .shadow(color: Color(red: 1.0, green: 0.55, blue: 0.0).opacity(glowPulse), radius: 15)
        .onAppear {
            withAnimation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
                glowPulse = 1.0
            }
        }
    }
}

// MARK: - 黄金VIP卡片
struct GoldVIPCard: View {
    let username: String
    let timeAgo: String
    let avatarURL: String?
    
    @State private var sparkleOpacity: Double = 0.5
    @State private var sparkleScale: CGFloat = 1.0
    
    var body: some View {
        ZStack {
            // 黄金渐变背景
            LinearGradient(
                colors: [
                    Color(red: 0.72, green: 0.53, blue: 0.04),
                    Color(red: 1.0, green: 0.84, blue: 0.0),
                    Color(red: 1.0, green: 1.0, blue: 0.6)
                ],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
            
            VStack(alignment: .leading, spacing: 12) {
                // 用户信息行
                HStack {
                    AsyncImage(url: URL(string: avatarURL ?? "")) { image in
                        image
                            .resizable()
                            .interpolation(.none)
                    } placeholder: {
                        Rectangle().fill(Color.gray.opacity(0.6))
                    }
                    .frame(width: 40, height: 40)
                    .border(Color.gray.opacity(0.8), width: 1)
                    
                    VStack(alignment: .leading, spacing: 2) {
                        Text(username)
                            .font(.custom("Menlo", size: 10))
                            .foregroundColor(.green)
                        
                        Text(timeAgo)
                            .font(.custom("Menlo", size: 6))
                            .foregroundColor(.gray)
                    }
                    
                    Spacer()
                    
                    // 闪电装饰
                    Text("⚡💎⚡")
                        .font(.custom("Menlo", size: 8))
                        .foregroundColor(.yellow)
                        .opacity(sparkleOpacity)
                        .scaleEffect(sparkleScale)
                }
                
                // 内容
                VStack(alignment: .leading, spacing: 6) {
                    Text("⚡ 黄金VIP闪耀登场!")
                        .font(.custom("Menlo", size: 9))
                        .fontWeight(.bold)
                        .foregroundColor(.black)
                    
                    VStack(alignment: .leading, spacing: 3) {
                        Text("⚡ 无限下载次数")
                        Text("🎨 AI皮肤定制服务")
                        Text("💛 专属黄金光效")
                        Text("🎪 优先客服支持")
                    }
                    .font(.custom("Menlo", size: 8))
                    .foregroundColor(.black)
                }
                
                // 统计信息
                HStack(spacing: 15) {
                    Text("💛 黄金特权")
                    Text("⚡ 无限制访问")
                }
                .font(.custom("Menlo", size: 7))
                .foregroundColor(.black.opacity(0.8))
            }
            .padding(16)
        }
        .border(Color(red: 1.0, green: 0.76, blue: 0.03), width: 2)
        .shadow(color: Color.yellow.opacity(0.8), radius: 10)
        .onAppear {
            withAnimation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
                sparkleOpacity = 1.0
                sparkleScale = 1.2
            }
        }
    }
}

// MARK: - 彩虹VIP卡片
struct RainbowVIPCard: View {
    let username: String
    let timeAgo: String
    let avatarURL: String?
    
    @State private var rainbowOffset: CGFloat = 0
    
    var body: some View {
        ZStack {
            // 彩虹流动背景
            LinearGradient(
                colors: [
                    .red, .orange, .yellow, .green, .blue, .purple
                ],
                startPoint: .leading,
                endPoint: .trailing
            )
            .offset(x: rainbowOffset)
            .animation(
                Animation.linear(duration: 3)
                    .repeatForever(autoreverses: false),
                value: rainbowOffset
            )
            
            VStack(alignment: .leading, spacing: 12) {
                // 用户信息行
                HStack {
                    AsyncImage(url: URL(string: avatarURL ?? "")) { image in
                        image
                            .resizable()
                            .interpolation(.none)
                    } placeholder: {
                        Rectangle().fill(Color.gray.opacity(0.6))
                    }
                    .frame(width: 40, height: 40)
                    .border(Color.gray.opacity(0.8), width: 1)
                    
                    VStack(alignment: .leading, spacing: 2) {
                        HStack {
                            Text(username)
                                .font(.custom("Menlo", size: 10))
                                .foregroundColor(.green)
                            
                            Text("限量版")
                                .font(.custom("Menlo", size: 6))
                                .foregroundColor(.white)
                                .padding(.horizontal, 4)
                                .padding(.vertical, 1)
                                .background(
                                    LinearGradient(
                                        colors: [.red, .pink],
                                        startPoint: .leading,
                                        endPoint: .trailing
                                    )
                                )
                        }
                        
                        Text(timeAgo)
                            .font(.custom("Menlo", size: 6))
                            .foregroundColor(.gray)
                    }
                    
                    Spacer()
                }
                
                // 内容
                VStack(alignment: .leading, spacing: 6) {
                    Text("🌈 彩虹至尊VIP震撼开启!")
                        .font(.custom("Menlo", size: 9))
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .shadow(color: .black.opacity(0.5), radius: 1)
                    
                    VStack(alignment: .leading, spacing: 3) {
                        Text("🎪 独家彩虹皮肤系列")
                        Text("🎊 专属彩虹称号")
                        Text("🎁 限时彩虹礼包")
                        Text("🌟 终身VIP特权")
                    }
                    .font(.custom("Menlo", size: 8))
                    .foregroundColor(.white)
                    .shadow(color: .black.opacity(0.3), radius: 1)
                }
                
                // 统计信息
                HStack(spacing: 15) {
                    Text("🌈 彩虹效果")
                    Text("🎉 限量发售")
                }
                .font(.custom("Menlo", size: 7))
                .foregroundColor(.white.opacity(0.9))
            }
            .padding(16)
        }
        .border(Color.white, width: 2)
        .shadow(color: .purple.opacity(0.6), radius: 15)
        .onAppear {
            withAnimation(Animation.linear(duration: 3).repeatForever(autoreverses: false)) {
                rainbowOffset = 100
            }
        }
    }
}

// MARK: - 粒子效果组件
struct ParticleView: View {
    let delay: Double
    @State private var yOffset: CGFloat = 0
    @State private var opacity: Double = 0.7
    @State private var rotation: Double = 0
    
    var body: some View {
        Rectangle()
            .fill(Color.yellow)
            .frame(width: 4, height: 4)
            .opacity(opacity)
            .offset(y: yOffset)
            .rotationEffect(.degrees(rotation))
            .position(
                x: CGFloat.random(in: 50...250),
                y: CGFloat.random(in: 50...150)
            )
            .onAppear {
                withAnimation(
                    Animation.easeInOut(duration: 3)
                        .repeatForever(autoreverses: true)
                        .delay(delay)
                ) {
                    yOffset = -10
                    opacity = 1.0
                    rotation = 180
                }
            }
    }
}

// MARK: - 预览和使用示例
struct VIPFeedCard_Previews: PreviewProvider {
    static var previews: some View {
        ScrollView {
            VStack(spacing: 20) {
                VIPFeedCard(
                    vipType: .flame,
                    username: "DragonSlayer_2024",
                    timeAgo: "刚刚",
                    avatarURL: nil
                )
                
                VIPFeedCard(
                    vipType: .lava,
                    username: "MasterBuilder",
                    timeAgo: "5分钟前",
                    avatarURL: nil
                )
                
                VIPFeedCard(
                    vipType: .gold,
                    username: "CrystalKnight",
                    timeAgo: "10分钟前",
                    avatarURL: nil
                )
                
                VIPFeedCard(
                    vipType: .rainbow,
                    username: "RainbowWarrior",
                    timeAgo: "15分钟前",
                    avatarURL: nil
                )
            }
            .padding()
        }
//        .background(
//            LinearGradient(
//                colors: [
//                    Color(red: 0.1, green: 0.1, blue: 0.18),
//                    Color(red: 0.09, green: 0.13, blue: 0.24)
//                ],
//                startPoint: .top,
//                endPoint: .bottom
//            )
//        )
    }
}

增加一个外发光效果代码

12.gif

//
//  JoinVipCard2.swift
//  mc skin
//
//  Created by martin on 2025/5/22.
//  Copyright © 2025 edgewise. All rights reserved.
//

import SwiftUI

struct JoinVipCard2: View {
    @Environment(\.colorScheme) var colorScheme
    @State private var isGlowing = false
    
    var body: some View {
        ZStack{
        VStack(alignment: .leading, spacing: 15) {
            // 钻石闪烁效果
            HStack {
                Spacer()
                Text("✨💎✨")
                    .font(.system(size: 12))
                    .opacity(0.8)
                    .scaleEffect(1.0)
                    .animation(
                        Animation.easeInOut(duration: 2)
                            .repeatForever(autoreverses: true),
                        value: UUID()
                    )
            }
            
            //            // 用户信息
            //            HStack {
            //                Circle()
            //                    .fill(Color.gray.opacity(0.3))
            //                    .frame(width: 40, height: 40)
            //
            //                VStack(alignment: .leading) {
            //                    Text("CrystalKnight")
            //                        .font(.system(size: 12, weight: .bold))
            //                        .foregroundColor(.green)
            //
            //                    Text("10分钟前")
            //                        .font(.system(size: 8))
            //                        .foregroundColor(.gray)
            //                }
            //            }
            
            // 内容
            VStack(alignment: .leading, spacing: 8) {
                Text("💎 钻石VIP闪亮登场!")
                    .font(.system(size: 10, weight: .bold))
                
                VStack(alignment: .leading, spacing: 4) {
                    Text("⚡ 无限下载次数")
                    Text("🎨 AI皮肤定制服务")
                    Text("🌈 专属钻石光效")
                    Text("🎪 优先客服支持")
                }
                .font(.system(size: 10))
            }
            .foregroundStyle(.white)
            
            // 统计信息
            HStack(spacing: 20) {
                HStack(spacing: 5) {
                    Text("💎")
                    Text("钻石特权")
                }
                
                HStack(spacing: 5) {
                    Text("⚡")
                    Text("无限制访问")
                }
            }
            .font(.system(size: 8))
            .foregroundColor(.gray)
        }
    }
        .frame(width:320, height:160)
        .padding(20)
        .background(
//            LinearGradient(
//                gradient: Gradient(colors: [
//                    colorScheme == .dark ? Color(hex: "FF8C00") : Color(hex: "FFA500"),
//                    colorScheme == .dark ? Color(hex: "FFA500") : Color(hex: "FFD700"),
//                    colorScheme == .dark ? Color(hex: "FFD700") : Color(hex: "FFFF00")
//                ]),
//                startPoint: .topLeading,
//                endPoint: .bottomTrailing
//            )
        )
        .cornerRadius(12)
        .overlay(
            RoundedRectangle(cornerRadius: 12)
                .stroke(Color(hex: "ffd400"), lineWidth: 3)
        )
        .shadow(
            color: Color(hex: "ffd400").opacity(isGlowing ? 0.8 : 0.3),
            radius: isGlowing ? 20 : 10,
            x: 0,
            y: 0
        )
        .onAppear {
            // 创建1Hz的定时器
            Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
                withAnimation(.easeInOut(duration: 0.5)) {
                    isGlowing.toggle()
                }
            }
        }
    }
}

// 颜色扩展
extension Color {
    init(hex: String) {
        let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        var int: UInt64 = 0
        Scanner(string: hex).scanHexInt64(&int)
        let a, r, g, b: UInt64
        switch hex.count {
        case 3: // RGB (12-bit)
            (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
        case 6: // RGB (24-bit)
            (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
        case 8: // ARGB (32-bit)
            (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
        default:
            (a, r, g, b) = (1, 1, 1, 0)
        }
        self.init(
            .sRGB,
            red: Double(r) / 255,
            green: Double(g) / 255,
            blue:  Double(b) / 255,
            opacity: Double(a) / 255
        )
    }
}

struct JoinVipCard2_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            JoinVipCard2()
                .preferredColorScheme(.light)
                .previewDisplayName("Light Mode")
            
            JoinVipCard2()
                .preferredColorScheme(.dark)
                .previewDisplayName("Dark Mode")
        }
        .padding()
//        .background(.black)
    }
}