ios - 在 SwiftUI 中为圆角矩形创建均匀分布的虚线轮廓

标签 ios swift swiftui swiftui-list swiftui-layout

编辑:代码示例中的破折号大小 10 是任意的。破折号的大小是任何看起来合适的大小。

假设在 SwiftUI 中,您想要一个具有虚线轮廓的自定义列表项 - 用作“添加项提示”。

所以你使用这样的描边边框:

struct ContentView: View {
    
    let items:[String] = ["a","b","c"]
    @State var itemsEmpty = false
    
    var body: some View {
        Text("toggle").onTapGesture {
            itemsEmpty.toggle()
        }
        VStack {
            Spacer()
            if !itemsEmpty {
                List{
                    ForEach(items, id: \.self) {item in
                        Text(item)
                    }
                }
            } else {
                // The "list item hint" view
                List{
                    Text("ADD")
                        .listRowBackground(
                            RoundedRectangle(cornerSize: CGSize(width: 15, height: 15))
                                .strokeBorder(style: StrokeStyle(lineWidth: 4, dash: [10]))
                            
                        )
                }
            }
            Spacer()
        }
        .padding()
    }
}

结果如下:

enter image description here

this Apple sample 中使用了相同的技术,但这对我来说并不满意,因为线条(可以理解)分布不均匀,并且我们在环绕点处得到了令人讨厌的截断。

我能想到的解决这个问题的唯一(也不能令人满意)的方法是:

A) 使用两个镜像形状来创建 View ...(但这仍然会导致截断...只是这次是对称截断)。

B) 制作某种“太阳光线”径向渐变并堆叠两个圆角矩形,给人一种虚线轮廓的错觉......(但这些线的“头和尾”不会是垂直于轮廓路径,因为“太阳光线”全部源自单个点)

C) 使用方圆的参数方程(方圆是因为如果是矩形,超椭圆在我看来就像废话)(需要将其切成两半并像豪华轿车一样拉伸(stretch))并从中创建一条路径,然后绘制沿着该路径以断续线的形式使用 t = 2 * (pi)/某个除数来建立分辨率。这样做的问题是修改后的(豪华轿车式)形状将是分段函数,因此不能由 t 驱动。另外,即使可能,破折号的大小也不会是规则的,因为一些明显的原因我无法用语言表达。

这怎么办?

最佳答案

如果笔画的长度(形状的周长)是破折号大小的整数倍,则破折号不会被截断。

因此,需要根据周长动态调整破折号的大小。请参阅thisthis分别用于查找参数曲线和非参数曲线的弧长。如果这太难集成,还可以考虑计算形状的基础 CGPath 中每个 CGPathElement 的长度。请参阅this gist (尽管它是用 Swift 2 编写的),或 this repo了解如何执行此操作。

对于带有圆角半径的圆角矩形,只需将直线部分和圆形部分的长度相加即可。

.listRowBackground(
    GeometryReader { geo in
        let strokeWidth: CGFloat = 4
        let radius: CGFloat = 15
        let insettedDiameter = radius * 2 - strokeWidth
        let desiredDash: CGFloat = 10
        // note that we need to take the inset of strokeBorder into account
        // or just use stroke instead of strokeBorder to make this simpler
        let perimeter = (geo.size.width - strokeWidth / 2 - insettedDiameter) * 2 + // horizontal straight edges
                        (geo.size.height - strokeWidth / 2 - insettedDiameter) * 2 + // vertical straight edges
                        (insettedDiameter * .pi) // the circular parts

        // this finds the smallest adjustedDash such that
        // - perimeter is an integer multiple of adjustedDash
        // - adjustedDash > desiredDash
        let floored = floor(perimeter / desiredDash)
        let adjustedDash = (perimeter - desiredDash * floored) / floored + desiredDash
        
        RoundedRectangle(cornerRadius: radius)
            .strokeBorder(style: StrokeStyle(lineWidth: strokeWidth, dash: [adjustedDash]))
    }
)

示例输出:

enter image description here

关于ios - 在 SwiftUI 中为圆角矩形创建均匀分布的虚线轮廓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77740803/

相关文章:

ios - Swift 将数据映射到 [String : Any]

json - id 解码 JSON 时找不到 key

php - key 中的 AES-128 UTF-8 字符 (iOS ↔ PHP)

ios - 将 Stackview 添加到 UIScrollView

objective-c - 如何以任意顺序比较两个 NSArrays 的相同内容?

iOS Spritekit intersectsnode 不适用于 SKShapeNode

ios - 我有一个场景,我想添加3天/5天吃药的通知。根据用户要求进行提醒

ios - 如果顶部有标题 View ,如何在 SwiftUI 列表下正确显示数据

swiftui - 如何对齐 View 底部尾随,覆盖在 SwiftUI 中剪辑在屏幕边缘的另一个 View 上?

ios - NSIndexPath? Swift 中没有成员名称 'row' 错误