我的应用程序工作正常,但有很多重复的代码.

我不知道如何重构GeometryReader,也不知道如何使用ForEach更改代码以符合MVVM设计模式.最后,这个应该放到垂直的ScrollView中吗?

任何方向都可以学习如何编写更简洁的SWIFT代码.

import SwiftUI

struct ContentView: View {
    
    let colorFriendship = LinearGradient(colors: [Color("ColorFriendshipLight"), Color("ColorFriendshipDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    let colorWealth = LinearGradient(colors: [Color("ColorWealthLight"), Color("ColorWealthDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    let colorEducation = LinearGradient(colors: [Color("ColorEducationLight"), Color("ColorEducationDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    let colorCareer = LinearGradient(colors: [Color("ColorCareerLight"), Color("ColorCareerDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    let colorFamily = LinearGradient(colors: [Color("ColorFamilyLight"), Color("ColorFamilyDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    let colorHealth = LinearGradient(colors: [Color("ColorHealthLight"), Color("ColorHealthDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    let colorSpirituality = LinearGradient(colors: [Color("ColorSpiritualityLight"), Color("ColorSpiritualityDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    let colorCompose = LinearGradient(colors: [Color("ColorComposeLight"), Color("ColorComposeDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
    
    // Shadow Icons
    private var radius = 7
    private var xOffset = 6
    private var yOffset = 6
    
    var body: some View {
        
        VStack {
            NavigationView {
                VStack {
                    HStack {
                        NavigationLink(destination: FriendshipListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-friendship")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorCareerDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                }
                                Text("Friendships")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(20)
                            .background(colorFriendship)
                            .cornerRadius(20)
                        }
                        NavigationLink(destination: WealthListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-wealth")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorWealthDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                }
                                Text("Wealth")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(20)
                            .background(colorWealth)
                            .cornerRadius(20)
                        }
                    }
                    HStack {
                        NavigationLink(destination: EducationListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-education")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorEducationDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                        
                                }
                                Text("Education")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(30)
                            .background(colorEducation)
                            .cornerRadius(20)
                        }
                        NavigationLink(destination: CareerListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-career")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorCareerDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                }
                                Text("Career")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(30)
                            .background(colorCareer)
                            .cornerRadius(20)
                        }
                    }
                    HStack {
                        NavigationLink(destination: FamilyListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-family")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorFamilyDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                }
                                Text("Family")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(30)
                            .background(colorFamily)
                            .cornerRadius(20)
                        }
                        NavigationLink(destination: HealthListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-health")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorHealthDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                }
                                Text("Health")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(30)
                            .background(colorHealth)
                            .cornerRadius(20)
                        }
                    }
                    HStack {
                        NavigationLink(destination: SpiritualityListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-spirituality")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorSpiritualityDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                }
                                Text("Spirituality")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(30)
                            .background(colorSpirituality)
                            .cornerRadius(20)
                        }
                        NavigationLink(destination: ComposeListView()) {
                            VStack(alignment: .center) {
                                GeometryReader { geo in
                                    Image("menu-icon-compose")
                                        .resizable()
                                        .scaledToFit()
                                        .frame(
                                            width: geo.size.width,
                                            height: geo.size.height)
                                        .shadow(color: Color("ColorSpiritualityDark"), radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                                }
                                Text("Compose")
                                    .titleStyle()
                            }
                            .frame(maxWidth: .infinity, maxHeight: 110)
                            .padding(30)
                            .background(colorCompose)
                            .cornerRadius(20)
                        }
                    }
                }
                .navigationTitle("Main Menu")
            }
        }
        .padding(.horizontal)
    }
    
}

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

// Custom modifiers

// MenuTitle
struct MenuTitle: ViewModifier {
    func body(content: Content) -> some View {
        content
            .font(.system(.title2, design: .rounded))
            .foregroundColor(.white)
            .fontWeight(.regular)
            .shadow(color: Color(.black), radius: 7, x: 2, y: 2)
    }
}

extension View {
    func titleStyle() -> some View {
        modifier(MenuTitle())
    }
}

// Struct List Views

struct FriendshipListView:View {
    var body: some View {
        Text("Friendship List")
    }
}

struct WealthListView:View {
    var body: some View {
        Text("Wealth List")
    }
}

struct EducationListView:View {
    var body: some View {
        Text("Education List")
    }
}

struct CareerListView:View {
    var body: some View {
        Text("Career List")
    }
}

struct FamilyListView:View {
    var body: some View {
        Text("Family List")
    }
}

struct HealthListView:View {
    var body: some View {
        Text("Health List")
    }
}

struct SpiritualityListView:View {
    var body: some View {
        Text("Spirituality List")
    }
}
struct ComposeListView:View {
    var body: some View {
        Text("Compose List")
    }
}

iPhone 11 Simulator Screenshot

推荐答案

要重构它,您首先需要创建某种类型的数据模型,该模型包含与您想要显示的每个主题相关的不同信息.

免责声明:

我不打算发布一个完整的工作示例.所以没必要问我要什么.但我会试着给你指个正确的方向.


首先创建一个enum,它定义了您想要显示的所有不同主题.我只实现了两个 case ,并不是所有的属性,但它背后的 idea 应该会变得清晰.

enum Topic: CaseIterable, Identifiable{
    // all the topics
    case friendship, wealth
    
    // to conform to Identifiable
    var id: Topic { self }
    
    // create the background gradient
    var background: LinearGradient{
        switch self{
        case .friendship:
            return LinearGradient(colors: [Color("ColorFriendshipLight"), Color("ColorFriendshipDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
        case .wealth:
            return LinearGradient(colors: [Color("ColorWealthLight"), Color("ColorWealthDark")], startPoint: .topLeading, endPoint: .bottomTrailing)
        }
    }
    
    // the image names
    var imagename: String{
        switch self{
        case .friendship:
            return "menu-icon-friendship"
        case .wealth:
            return "menu-icon-wealth"
        }
    }

    // here you create the target view. If the views need to get properties set, you can give your enum cases assosiated values and add them during initialization    
    @ViewBuilder
    var targetView: some View{
        switch self{
        case .friendship:
            FriendshipListView()
        case .wealth:
            WealthListView()
        }
    }
}

使用LazyVGrid,查看就会变得非常简单:

struct ContentView: View{

    let columns = [GridItem(.flexible()), .init(.flexible())]
    
    var body: some View{
        NavigationView{
            ScrollView{
                LazyVGrid(columns: columns) {
                    // iterate over all topics
                    ForEach(Topic.allCases){ topic in
                    // create you reusable view and pass the data into it
                        CardView(topic: topic)
                    }
                }
            }
        }
    }
}

// this view will be reused for displayin the topics
struct CardView: View{
    
    let topic: Topic
    // Shadow Icons
    private let radius = 7
    private let xOffset = 6
    private let yOffset = 6
    
    var body: some View{
        NavigationLink(destination: topic.targetView) {
            VStack(alignment: .center) {
                // I don´t think you need the geometry reader here but 
                // I don´t know how your view will look without it
                GeometryReader { geo in
                    Image(topic.imagename)
                        .resizable()
                        .scaledToFit()
                        .frame(
                            width: geo.size.width,
                            height: geo.size.height)
                        .shadow(color: topic.shadowColor, radius: CGFloat(radius), x: CGFloat(xOffset), y: CGFloat(yOffset))
                        
                }
                Text(topic.title)
                    .titleStyle()
            }
            .frame(maxWidth: .infinity, maxHeight: 110)
            .padding(30)
            .background(topic.background)
            .cornerRadius(20)
        }
    }
}

Ios相关问答推荐

自定义油漆圆角三角形

当包含UITextView的inputAccessoryView显示键盘时,iOS UITableView内容会出现UINavigationBar奇怪的错误

如何使用超薄material ,但没有浅色/填充?

如何将模糊输入/模糊输出添加到SwiftUI中的非对称过渡?

如何结合`@dynamicMemberLookup`和`ExpressibleByStringInterpolation`来实现方法链?

如何在SwiftUI中实现淡入淡出加粘标题屏幕效果

由于缺少 libarclite_iphonesimulator.a 文件,将 XCode 升级到 14.3 后无法在模拟器上运行 Flutter 应用程序

SwiftUI 每秒从 Timer 更新单个 @State 属性,每秒也重绘整个视图

渲染的海边重定向在物理 iOS 设备上不起作用

迁移到 UIKit 生命周期的应用程序不会调用 SceneDelegate

AVPlayer 退出全屏

.overlay 和 body 是什么 swift 概念

SignalR 永远不会在 iOS 上使用 Xamarin Forms 启动

如何将标准化坐标系中的点的位置转换为具有相对位置的常规坐标系?

UICollectionView - 动态单元格高度?

无法验证客户端 3000

没有 Mac 的 Xamarin Visual Studio IOS 开发?

SwiftUI NavigationView navigationBarTitle LayoutConstraints 问题

SRCROOT 和 PROJECT_DIR 有什么区别?

如何检测快速touch 或单击的tableView单元格