如何修改拖放预览SwiftUI的背景颜色和形状?

Posted

技术标签:

【中文标题】如何修改拖放预览SwiftUI的背景颜色和形状?【英文标题】:How do I modify the background color and shape of drag&drop preview 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) 有圆角形状,没有白框

我怎样才能实现它?

【问题讨论】:

【参考方案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 的类似问题,但遗憾的是,根本没有任何答案或示例……***.com/questions/67248900/… 我也无法让样本工作,但我把我尝试过的放在上面。我将把它作为错误报告发送

以上是关于如何修改拖放预览SwiftUI的背景颜色和形状?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 列表中设置选定的行背景颜色?

在 SwiftUI 中修改 List 的背景颜色?

我可以在 SwiftUI 中反转 clipShape 以从另一个形状中剪出形状吗?

SwiftUI onDrag 在设备上运行时不显示预览图像

SwiftUI 按钮大小/形状/颜色不变

如何修改 SwiftUI 预览的 UIView 属性?