我正试图在SwiftUI中定义这样的 struct :

expected

为了描述这一点,我需要创建5个类似于此 struct 的按钮.我需要有一个按钮的顶部,右侧,左侧,底部和中心,并给用户的能力,以改变 colored颜色 时,用户点击每一侧 Select 或如果用户点击中心 Select ,我可以改变 colored颜色 . 我的代码是:

import SwiftUI

struct OdontogramComponentView: View {
    
    @State private var leftButtonColor = Color.blue
    @State private var leftBorderColor = Color.black
    @State private var rightButtonColor = Color.red
    @State private var rightBorderColor = Color.black
    @State private var leftButtonPressed = false
    @State private var rightButtonPressed = false
    
    var body: some View {
        ZStack {
            HStack(spacing: 0) {
                Button(action: {
                    self.leftButtonPressed = true
                    self.rightButtonPressed = false
                    self.changeLeftButtonColor()
                }) {
                    Text("")
                        .foregroundColor(.white)
                        .frame(width: 40, height: 80)
                        .background(leftButtonColor)
                        .border(width: 2, edges: [.top, .leading, .bottom], color: leftBorderColor)
                }
                
                Button(action: {
                    self.leftButtonPressed = false
                    self.rightButtonPressed = true
                    self.changeRightButtonColor()
                }) {
                    Text("")
                        .foregroundColor(.white)
                        .frame(width: 40, height: 80)
                        .background(rightButtonColor)
                        .border(width: 2, edges: [.top, .trailing, .bottom], color: rightBorderColor)
                }
            }
            
            Rectangle()
                .fill(Color.black)
                .frame(width: 110, height: 2)
                .offset(x: 0, y: 0)
                .rotationEffect(.degrees(45))
            
            Rectangle()
                .fill(Color.black)
                .frame(width: 2, height: 110)
                .offset(x: 0, y: 0)
                .rotationEffect(.degrees(45))
            
            Button(action: {
                self.leftButtonPressed = false
                self.rightButtonPressed = false
                self.changeLeftButtonColor()
                self.changeRightButtonColor()
            }) {
                Image(systemName: "")
                    .foregroundColor(.white)
                    .font(.system(size: 20, weight: .bold))
                    .frame(width: 40, height: 40)
                    .background(leftButtonColor)
                    .border(leftBorderColor, width: 2)
            }
        }
        .frame(width: 120, height: 120)
    }
    
    private func changeLeftButtonColor() {
        if leftButtonPressed {
            switch leftButtonColor {
            case .blue:
                leftButtonColor = .red
                leftBorderColor = .black
            case .red:
                leftButtonColor = .white
                leftBorderColor = .black
            case .white:
                leftButtonColor = .blue
                leftBorderColor = .black
            default:
                break
            }
        }
    }
    
    private func changeRightButtonColor() {
        if rightButtonPressed {
            switch rightButtonColor {
            case .blue:
                rightButtonColor = .red
                rightBorderColor = .black
            case .red:
                rightButtonColor = .white
                rightBorderColor = .black
            case .white:
                rightButtonColor = .blue
                rightBorderColor = .black
            default:
                break
            }
        }
    }
}

并添加视图扩展和其他元素

import SwiftUI

extension View {
    
    func border(width: CGFloat, edges: [Edge], color: Color) -> some View {
        overlay(EdgeBorder(width: width, edges: edges).foregroundColor(color))
    }
}

添加这个 struct 来创建不可见的线,没有左和右,因为我只有两个按钮,一个在中央按钮下,一个在左边

import SwiftUI

struct EdgeBorder: Shape {
    var width: CGFloat
    var edges: [Edge]

    func path(in rect: CGRect) -> Path {
        edges.map { edge -> Path in
            switch edge {
            case .top: return Path(.init(x: rect.minX, y: rect.minY, width: rect.width, height: width))
            case .bottom: return Path(.init(x: rect.minX, y: rect.maxY - width, width: rect.width, height: width))
            case .leading: return Path(.init(x: rect.minX, y: rect.minY, width: width, height: rect.height))
            case .trailing: return Path(.init(x: rect.maxX - width, y: rect.minY, width: width, height: rect.height))
            }
        }.reduce(into: Path()) { $0.addPath($1) }
    }
}

My result is this: result

推荐答案

如果任何人有更好的解决方案/ idea ,这是我的解决方案,或者如果任何人发现这个解决方案有用,你可以复制你的项目.

import SwiftUI

// MARK: - Left and top
enum SquareLeftAndTopSection {
    
    case left
    case top
    
    var points: [CGPoint] {
        switch self {
        case .left:
            return [
                .init(x: 0, y: 200),
                .init(x: 50, y: 150),
                .init(x: 50, y: 50)
            ]
        case .top:
            return [
                .init(x: 200, y: 0),
                .init(x: 150, y: 50),
                .init(x: 50, y: 50)
            ]
        }
    }
}

struct SquareLeftAndTopShapeView: View {
    
    var type: SquareLeftAndTopSection
    @State var color: Color = .white
    @State var tapCount: Int = 0
    
    var body: some View {
        Path { path in
            path.move(to: CGPoint(x: 0, y: 0))
            type.points.forEach { path.addLine(to: $0) }
            path.closeSubpath()
        }
        .fill(color)
        .overlay(
            RoundedRectangle(cornerRadius: 8)
                .stroke(Color.black, lineWidth: 1)
                .padding(.all, -10)
        )
        .padding(.leading)
        .gesture(
            TapGesture()
                .onEnded({
                    tapCount += 1
                    switch tapCount {
                    case 1:
                        color = .blue
                    case 2:
                        color = .red
                    case 3:
                        color = .white
                        tapCount = 0
                    default:
                        break
                    }
                })
        )
    }
}

// MARK: - Right and bottom
enum SquareRightAndBottomSection {
    
    case right
    case bottom
    
    var points: [CGPoint] {
        switch self {
        case .right:
            return [
                .init(x: 0, y: 200),
                .init(x: 50, y: 150),
                .init(x: 150, y: 150)
            ]
        case .bottom:
            return [
                .init(x: 200, y: 0),
                .init(x: 150, y: 50),
                .init(x: 150, y: 150)
            ]
        }
    }
}

struct SquareRightAndBottomShapeView: View {
    
    var type: SquareRightAndBottomSection
    @State var color: Color = .white
    @State var tapCount: Int = 0
    
    var body: some View {
        Path { path in
            path.move(to: CGPoint(x: 200, y: 200))
            type.points.forEach { path.addLine(to: $0) }
            path.closeSubpath()
        }
        .fill(color)
        .overlay(
            RoundedRectangle(cornerRadius: 8)
                .stroke(Color.black, lineWidth: 1)
                .padding(.all, -10)
        )
        .padding(.leading)
        .gesture(
            TapGesture()
                .onEnded({
                    tapCount += 1
                    switch tapCount {
                    case 1:
                        color = .blue
                    case 2:
                        color = .red
                    case 3:
                        color = .white
                        tapCount = 0
                    default:
                        break
                    }
                })
        )
    }
}

// MARK: - Center
struct SquareCenterShapeView: View {
    
    @State private var color: Color = .white
    @State private var tapCount: Int = 0
    
    var body: some View {
        Rectangle()
            .fill(color)
            .frame(width: 100, height: 100)
            .overlay(
                RoundedRectangle(cornerRadius: 8)
                    .stroke(Color.black, lineWidth: 1)
            )
            .padding(.leading, 12)
            .gesture(
                TapGesture()
                    .onEnded({
                        tapCount += 1
                        switch tapCount {
                        case 1:
                            color = .blue
                        case 2:
                            color = .red
                        case 3:
                            color = .white
                            tapCount = 0
                        default:
                            break
                        }
                    })
            )
    }
}

struct SquareComponenteView: View {
    
    var topNumber: Int? = 0
    var bottomNumber: Int? = 0
    
    var body: some View {
        VStack {
            if let top = topNumber, top != 0 {
                Text("\(top)")
                    .font(.system(size: 24, weight: .bold, design: .default))
                    .padding(.top, 10)
            }
            ZStack {
                // MARK: - Defining Left and top
                SquareLeftAndTopShapeView(type: .left)
                SquareLeftAndTopShapeView(type: .top)
                
                // MARK: - Defining Right and bottom
                SquareRightAndBottomShapeView(type: .right)
                SquareRightAndBottomShapeView(type: .bottom)
                
                // MARK: - Defining Center
                SquareCenterShapeView()
            }
            .frame(width: 220, height: 200, alignment: .center)
            .padding([.trailing, .top, .bottom], 25)
            .padding(.leading, 10)
            
            if let bottom = bottomNumber, bottom != 0 {
                Text("\(bottom)")
                    .font(.system(size: 24, weight: .bold, design: .default))
                    .padding(.bottom, 10)
            }
        }
    }
}

当我点击任何部分时, colored颜色 的变化取决于touch 次数 And the result is some like this:

result

Swift相关问答推荐

如何在visionOS上删除PhotosPicker背景 colored颜色 ?

在SWIFTUI&39;S视图修改器中使用等待关键字

如何使泡泡上的箭头直达封闭矩形

如何在visionOS中将模型锚定在用户头部上方?

如何在 SwiftUI 中为过渡动画保持相同的标识

在 init(from decoder: Decoder) 方法中访问原始 JSON 数据

自定义碰撞形状出现在错误的位置

如何在 macOS/AppKit 的窗口选项卡上接受拖动项目的放置?

使用 WrappingHStack 文本溢出到新行

有没有更快的方法来循环浏览 macOS 上已安装的应用程序?

从 Swift Vapor Server 中调用 ShazamKit

RxSwift 事件触发了两次

故事板未在助手中显示视图控制器

引用类型(类)不需要但 struct 需要的可识别 id

Xcode:方法参数的代码完成

如何在 SwiftUI 的 fileImporter 中为 allowedContentTypes 设置 xcodeproj 类型?

UnkeyedEncodingContainer 和 KeyedEncodingContainerProtocol 中的 superEncoder 是什么?

在 Swift 4 中实现自定义解码器

try 在解除分配时加载视图控制器的视图... UIAlertController

用 UIBezierPath 画一条线