0

有人可以解释为什么我自己制作的符合 InsettableShape 的“myRectangle”不适用于 .strokeBorder 但内置的 Rectangle() 可以吗?

这是我的矩形代码;

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
    }
}

然后用 .strokeBorder 修改它;

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)
        
    }
}

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

预期风格

我得到了什么

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

我误解了一些东西还是这个修改器只适用于默认形状?

4

1 回答 1

1

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

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

我在您的代码中注意到的第一项是您在path(in rect: CGRect)方法中对某些值进行了硬编码,这就是为什么您的输出不是正方形的原因。有两种选择:

  1. 将宽度和高度变量添加到myRectangle并在您的中使用它们path(in rect: CGRect)来创建形状
  2. 使用 .frame() 的整个大小创建形状,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. 要插入一个矩形,您需要考虑到 SwiftUI 从左上角测量坐标,将每个边缘点向内插入量,因此您可以说左上角为 (0,0)
  3. 我在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自定义视图中,我只向.frame(width: 300, height: 300)您正在创建自定义形状的 ZStack 容器添加了一个修改器,以便我可以控制其大小。

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)
  }
}

有了这个,我能够得到彩虹效果。

希望这可以解决您的问题。

于 2020-12-08T16:24:37.483 回答