编辑:代码样例中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)改为使用两个镜像形状创建视图...(但这仍将导致截断...只是这一次将是对称截断).

B)制作某种"太阳射线"的径向渐变,将两个圆角矩形叠加在一起,给人一种虚线轮廓的错觉……(但这些线的"头和尾"不会垂直于轮廓路径,因为"太阳光"都是从一个点发出的)

C)将参数方程用于一个螺旋(Squircle,因为如果一个超椭圆是矩形的,它看起来就像垃圾一样)(它需要被切成两半,像豪华轿车一样拉伸),并从它创建一条路径,然后使用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 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 - radius) * 2 + // horizontal straight edges
                        (geo.size.height - strokeWidth / 2 - radius) * 2 + // vertical straight edges
                        (2 * .pi * (radius - strokeWidth / 2)) // 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相关问答推荐

不使用iOS 17修改器修改SWIFT用户界面视图

SWIFT根据地球坐标修改 node 旋转

如何使用Xcode15.1在iMessage扩展模块中显示贴纸

使用AVCaptureEventInteraction捕获音量按键快门

如何使用 SwiftData 从列表中删除子项目?

清除/删除 NavigationController 中的多个 ViewController

拖动手势导致 sim 崩溃 Swift UI

在iOS中使用Swift,即时更改应用语言后,立即改变外观会出现问题

如何更改 SwiftUI 弹出视图的大小?

ionic 4 - 编译 ios - 来自项目Pods的目标GoogleDataTransport中的问题

uikit中如何触发swiftui功能

为什么 Swift 不在启动的同一线程上恢复异步函数?

SwiftUI - 如何从主题感知命名 colored颜色 中获取正确的 RGB 值?

在iOS7半透明导航栏中获取正确的 colored颜色

UICollectionView 添加 UICollectionCell

如何以编程方式调用视图控制器?

如何从一个特定的视图控制器中隐藏导航栏

如何在 iPhone 中为透明的 PNG 图像着色?

如何在 Swift 中将新单元格插入 UITableView

NSURL 到带有 XCTest 的测试包中的文件路径