SwiftUI InsettableShape 与 .linesBorder

问题描述 投票:0回答:1

有人可以解释一下为什么我自己制作的符合 InsettableShape 的“myRectangle”不能与 .linesBorder 一起使用,但内置的 Rectangle() 可以吗?

这是 myRectangle 代码;

struct myRectangle: InsettableShape {
    var insetAmount: CGFloat = 0
    
    func path(in rect: CGRect) -> Path {
    var path = Path()
        
        path.move(to: CGPoint(x: rect.midX * 1.2, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.midX * 1.2, y: rect.midY * 0.6))
        path.addLine(to: CGPoint(x: rect.midX * 0.8, y: rect.midY * 0.6))
        path.addLine(to: CGPoint(x: rect.midX * 0.8, y: rect.maxY))
        
        return path
    }
    
    func inset(by amount: CGFloat) -> some InsettableShape {
        var rectangle = self
        rectangle.insetAmount -= amount
        return rectangle
    }
}

然后用 .linesBorder 修改它;

struct ColorCyclingRectangle: View {
    var amount = 0.0
    var steps = 100

    var body: some View {
        ZStack {
            ForEach(0..<steps) { value in
                myRectangle()
                    .inset(by: CGFloat(value))
                    .strokeBorder(self.color(for: value, brightness: 1), lineWidth: 2)
            }
        
        }
    .drawingGroup()
}

    func color(for value: Int, brightness: Double) -> Color {
        var targetHue = Double(value) / Double(self.steps) + self.amount
        
        if targetHue > 1 {
            targetHue -= 1
        }
        
        return Color(hue: targetHue, saturation: 1, brightness: brightness)
        
    }
}

我期待彩虹效果,但只是得到一条渐变线。

Expected style

What I am getting

我尝试将路径修改为 - insetAmount 但我只是得到一个奇怪的形状,并且彩虹边框是直的,而不是方形的

我是否误解了什么,或者此修改器仅适用于默认形状?

swiftui border shapes stroke insets
1个回答
3
投票

虽然这是一个较旧的问题,但我会尝试回答它,希望OP仍然感兴趣或者它可以帮助其他人。

您绝对可以在符合 InsettableShape 协议的自定义类型上使用 strokeBorder() 修饰符,注意您有责任编写相应的插入(减小大小)自定义形状的代码。

我在代码中注意到的第一件事是,您在

path(in rect: CGRect)
方法中对某些值进行了硬编码,这就是为什么您的输出不是正方形的原因。两个选项是:

  1. 将宽度和高度变量添加到 myRectangle 并在您的
    path(in rect: CGRect)
    中使用它们来创建形状
  2. 使用
    rect
    的整个大小创建形状,并在要创建自定义形状的容器上或直接在形状上使用 .frame() 修饰符来控制其尺寸。

我不确定哪个更好,但我将使用选项 2,因为这似乎是内置形状的工作方式 - 至少与宽度和高度相关 - 并且它使得更容易理解插入代码,如下所示

struct myRectangle: InsettableShape {
  var insetAmount: CGFloat = 0
  
  func path(in rect: CGRect) -> Path {
    var path = Path()
    path.move(to: CGPoint(x: rect.minX + insetAmount, y: rect.maxY - insetAmount))
    path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.maxY - insetAmount))
    path.addLine(to: CGPoint(x: rect.maxX - insetAmount, y: rect.minY + insetAmount))
    path.addLine(to: CGPoint(x: rect.minX + insetAmount, y: rect.minY + insetAmount))
    path.addLine(to: CGPoint(x: rect.minX + insetAmount, y: rect.maxY - insetAmount))
    
    return path
  }
  
  func inset(by amount: CGFloat) -> some InsettableShape {
    var rectangle = self
    rectangle.insetAmount += amount
    return rectangle
  }
}

在上面你会注意到:

  1. 我删除了 1.2、0.8 和 0.6,而是使用 minX、maxX、minY 和 maxY 来利用整个
    rect
    尺寸
  2. 创建形状
  3. 要插入矩形,您需要将每个边缘点向内移动插入量,考虑到 SwiftUI 从左上角开始测量坐标,因此您可以说左上角为 (0,0)
  4. 我在创建路径的
    path(in rect: CGRect)
    代码中使用了 insetAmount 变量。例如
    path.move(to: CGPoint(x: rect.minX + insetAmount, y: rect.maxY - insetAmount))
    是左下角。要插入这一点,您需要将 X 向右移动
    rect.minX + insetAmount
    ,将 Y 向上移动
    rect.maxY - insetAmount
    - 我们从 Y 中减去以根据我的点 2 向上移动。

在您的 ColorCyclingRectangle 自定义视图中,我仅向您要在其中创建自定义形状的 ZStack 容器添加了

.frame(width: 300, height: 300)
修饰符,以便我可以控制其大小。

struct ColorCyclingRectangle: View {
  var amount = 0.0
  var steps = 100

  var body: some View {
    ZStack {
      ForEach(0..<steps) { value in
        myRectangle()
          .inset(by: CGFloat(value))
          .strokeBorder(self.color(for: value, brightness: 1), lineWidth: 2)
      }
    }
    .drawingGroup()
    .frame(width: 300, height: 300)
  }

  func color(for value: Int, brightness: Double) -> Color {
    var targetHue = Double(value) / Double(self.steps) + self.amount
    
    if targetHue > 1 {
      targetHue -= 1
    }
    
    return Color(hue: targetHue, saturation: 1, brightness: brightness)
  }
}

这样我就能得到彩虹效果。

希望这能解决您的问题。

© www.soinside.com 2019 - 2024. All rights reserved.