ios 给定一个自定义Shape,如何在SwiftUI中增加大小以适合框架?

dffbzjpn  于 2023-04-08  发布在  iOS
关注(0)|答案(2)|浏览(148)

我有一系列自定义的Shape和一个ZStack,有一个固定的框架,有没有办法增加每个自定义Shape的大小,可以有各种大小,以适应Zstack框架?

将绘制各种Shape给定点的代码。

struct DrawShape: Shape {

    var points: [CGPoint]
    
    func path(in rect: CGRect) -> Path {
        var path: Path = Path()

        guard let startingPoint = points.first else {
            return path
        }

        path.move(to: startingPoint)

        for pointLocation in points {
            
            path.addLine(to: pointLocation)
            
        }

        return path
    }
}
yws3nbqq

yws3nbqq1#

我的想法是
1.像往常一样画出路径
1.获取路径的boundingRect

  • 确定路径所需的比例因子
    *rect是形状的可用面积
  • 如果boundingRectrect宽,则使用它们宽度
  • 如果boundingRectrect更细,则使用它们的高度
  • 绘制一条新的路径,这一次使用缩放的点和偏移量(如果需要)
  • 如果路径的原点不是(0, 0),则每个新点都需要减去原点
  • 返回新路径
struct DrawShape: Shape {
    var points: [CGPoint]
    
    func path(in rect: CGRect) -> Path {
        
        /// draw the path
        var path = Path()
        guard let startingPoint = points.first else { return path }
        path.move(to: startingPoint)
        for pointLocation in points {
            path.addLine(to: pointLocation)
        }
        
        /// aspect fit scale
        let scale: CGFloat
        if path.boundingRect.height / path.boundingRect.width < rect.height / rect.width {
            scale = rect.width / path.boundingRect.width /// boundingRect is fatter
        } else {
            scale = rect.height / path.boundingRect.height /// boundingRect is skinnier
        }

        /// draw the scaled path
        var scaledPath = Path()
        scaledPath.move(to: convertPoint(startingPoint, offset: path.boundingRect.origin, scale: scale))
        for pointLocation in points {
            scaledPath.addLine(to: convertPoint(pointLocation, offset: path.boundingRect.origin, scale: scale))
        }
        
        /// return the scaled path
        return scaledPath
    }
    
    /// point = original point
    /// offset = in case the origin of `boundingRect` isn't (0,0), make sure to offset each point
    /// scale = how much to scale the point by
    func convertPoint(_ point: CGPoint, offset: CGPoint, scale: CGFloat) -> CGPoint {
        return CGPoint(x: (point.x - offset.x) * scale, y: (point.y - offset.y) * scale)
    }
}

struct ContentView: View {
    var body: some View {
        ZStack {
            Color.blue
            
            DrawShape(points: [
                CGPoint(x: 0, y: 0),
                CGPoint(x: 200, y: 0),
                CGPoint(x: 100, y: 250),
                CGPoint(x: 0, y: 0)
            ])
        }
        .frame(width: 300, height: 500)
    }
}
之前之后


|

|

yyyllmsg

yyyllmsg2#

有一种方法可以在保持长宽比的情况下将任何路径放入矩形中,而且这种方法很短。

struct FittingShape: Shape {
    var absolutePath: Path
    
    func path(in rect: CGRect) -> Path {
        let boundingRect = absolutePath.boundingRect
        let scale = min(rect.width/boundingRect.width, rect.height/boundingRect.height)
        let scaled = absolutePath.applying(.init(scaleX: scale, y: scale))
        let scaledBoundingRect = scaled.boundingRect
        let offsetX = scaledBoundingRect.midX - rect.midX
        let offsetY = scaledBoundingRect.midY - rect.midY
        return scaled.offsetBy(dx: -offsetX, dy: -offsetY)
    }
}

测试它:

struct ContentView: View {
    var path = Path {
        $0.addLines([
            CGPoint(x: 0, y: 0),
            CGPoint(x: 200, y: 0),
            CGPoint(x: 100, y: 250),
            CGPoint(x: 0, y: 0)
        ])
    }
    
    var body: some View {
        ZStack {
            Color.blue
            FittingShape(absolutePath: path) // The shape is centered
            //DrawShape(points: points) // This gives sligtly different result: the shape is sticked to the top
        }
        .frame(width: 300, height: 500)
    }
}

相关问题