【问题标题】:How do I modify the background color and shape of drag&drop preview SwiftUI?如何修改拖放预览SwiftUI的背景颜色和形状?
【发布时间】:2021-09-28 14:48:18
【问题描述】:

我正在尝试使用可拖动单元格(iOS 15)实现简单列表。目前我有两个基本解决方案:List 和 ScrollView。这些方法都不会导致我得到适当的结果。

首先我会提供一些代码:

列表项视图:

struct ListItemView: View {
    let index: Int

    var body: some View {
        HStack {
            Text("Item \(index)")
                .foregroundColor(.white)
            Spacer()
        }
        .padding()
        .background(Color.gray)
        .clipShape(RoundedRectangle(cornerRadius: 16.0))
    }
}

第一个解决方案(使用列表):

struct ContentView: View {
    var body: some View {
        List(0 ..< 10) { i in
            ListItemView(index: i)
                .onDrag {
                    NSItemProvider(object: String(describing: "item_\(i)") as NSString)
                }
                .padding(.bottom, 8.0)
                .listRowBackground(Color.clear)
                .listRowSeparator(.hidden)
                .listRowInsets(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 8))
        }
        .background(Color.black)
        .listStyle(PlainListStyle())
    }
}

结果很好,但是当我开始拖动动作时,我看到我的单元格周围有一些白色矩形,这不是我想要的:

第二种解决方案(使用 ScrollView)

struct ContentView: View {
    var body: some View {
        ScrollView {
            ForEach(0 ..< 10) { i in
                ListItemView(index: i)
                    .onDrag {
                        NSItemProvider(object: String(describing: "item_\(i)") as NSString)
                    }
            }
        }
        .background(Color.black)
    }
}

结果有点不同:我们看不到任何彩色矩形(我想,这是因为我们没有使用 List 并且拖放功能的机制不同)。还有没有圆角的缩放预览和形状。

因此,理想的行为是: a) 预览的大小与列表项的原始大小相同 b) 有圆角形状,没有白框

我怎样才能实现它?

【问题讨论】:

    标签: ios swift swiftui swiftui-list swiftui-scrollview


    【解决方案1】:

    理论上,您的NSItemProvider 可以提供previewImageHandler,这是一个绘制您希望系统用作拖动预览的图像的块。不幸的是,这似乎不起作用。 onDrag 修饰符的文档说它使用视图的图片作为预览图像,它似乎忽略了previewImageHandler。如果有人发现其他情况,请发表评论,我会修改答案。这是我尝试过的:

    import SwiftUI
    
    struct ListItem : Identifiable {
        let id: Int
        let title: String
    }
    
    let itemsInList = (0..<10).map { ListItem(id: $0, title: "Item \($0)") }
    
    @ViewBuilder func ListItemView(title : String) -> some View {
        ZStack(alignment: .leading) {
            RoundedRectangle(cornerRadius: 18, style: .circular)
                .foregroundColor(Color(red: 142.0/255.0, green: 142.0/255.0, blue: 142.0/255.0, opacity: 1.0))
            Text(title)
                .foregroundColor(.white)
                .padding()
        }
    }
    
    struct ContentView: View {
        var body: some View {
            List(itemsInList) {
                let itemTitle = $0.title
                ListItemView(title: itemTitle)
                    .onDrag {
                        let itemProvider = NSItemProvider()
                        itemProvider.registerObject("Item \(itemTitle)" as NSString, visibility: .all)
                        itemProvider.previewImageHandler = {
                            (completionHandler, expectedClass, options) -> Void in
    
                            var resultImage : CGImage?
    
                            debugPrint(expectedClass ?? "Unknown")
                            if let cgContext = CGContext(data: nil,
                                                         width: 72,
                                                         height: 72,
                                                         bitsPerComponent: 8,
                                                         bytesPerRow: 16 * (((72 * 4) + 15) / 16),
                                                         space: CGColorSpace(name: CGColorSpace.sRGB)!,
                                                         bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue) {
    
                                let frame = CGRect(x: 0, y: 0, width: 72, height: 72)
                                cgContext.clear(frame)
                                cgContext.setFillColor(UIColor.red.cgColor)
                                cgContext.fillEllipse(in: frame)
    
                                resultImage = cgContext.makeImage()
                            }
    
                            if let completionHandler = completionHandler {
                                if let resultImage = resultImage {
                                    completionHandler(UIImage(cgImage: resultImage), nil)
                                } else {
                                    completionHandler(nil, NSError(domain: "ItemCompletion", code: -1, userInfo: nil))
                                }
                            }
                        }
    
                        return itemProvider
                    }
            }
        }
    }
    
    
    struct previews : PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    

    【讨论】:

    • 嗨,斯科特,谢谢你的回答!我试图为我的NSItemProvider 实现这个处理程序,但它没有被调用(我想,iOS 应该自己管理它)。我得到这个的唯一方法——我自己调用loadPreviewImage方法。您能否提供有关如何使用此处理程序的更多详细信息?附言我发现了关于previewImageHandler 的类似问题,但遗憾的是,根本没有任何答案或示例……stackoverflow.com/questions/67248900/…
    • 我也无法让样本工作,但我把我尝试过的放在上面。我将把它作为错误报告发送
    猜你喜欢
    • 2019-10-24
    • 2023-03-03
    • 2021-09-22
    • 2022-01-03
    • 2017-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多