简体   繁体   English

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

[英]How do I modify the background color and shape of drag&drop preview SwiftUI?

I'm trying to implement simple list with draggable cells (iOS 15).我正在尝试使用可拖动单元格(iOS 15)实现简单列表。 For now I have two base solutions: List and ScrollView.目前我有两个基本解决方案:List 和 ScrollView。 None of this methods doesn't lead me to appropriate result.这些方法都不会导致我得到适当的结果。

First of all I'll provide some code:首先,我将提供一些代码:

List item view:列表项视图:

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))
    }
}

First solution (using List):第一个解决方案(使用列表):

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())
    }
}

The result is fine, but when I start dragging action, I see some white rect around my cell, which is not what I want:结果很好,但是当我开始拖动动作时,我看到我的单元格周围有一些白色矩形,这不是我想要的:

使用 ScrollView 拖放预览

Second solution (using ScrollView)第二种解决方案(使用 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)
    }
}

The result is a bit different: we don't see any coloured rects (I suppose, this is because we are not using List and there is different mechanism of drag&drop feature).结果有点不同:我们看不到任何彩色矩形(我想,这是因为我们没有使用 List 并且拖放功能的机制不同)。 Also there is scaled preview and shape without rounded corners.还有没有圆角的缩放预览和形状。

使用列表拖放预览

So, the desirable behaviour is: a) the size of preview is the same as original size of list item b) there is rounded-corners shape without white frame因此,理想的行为是:a)预览的大小与列表项的原始大小相同 b)没有白框的圆角形状

How can I achieve it?我怎样才能实现它?

Theoretically your NSItemProvider can offer a previewImageHandler which is a block that draws the image you want the system to use as the drag preview.从理论上讲,您的NSItemProvider可以提供一个previewImageHandler ,它是一个绘制您希望系统用作拖动预览的图像的块。 Unfortunately that doesn't seem to work.不幸的是,这似乎不起作用。 The documentation of the onDrag modifier says that it uses a picture of the view as the preview image and it seemingly ignores the previewImageHandler . onDrag修饰符的文档说它使用视图的图片作为预览图像,它似乎忽略了previewImageHandler If someone finds out otherwise, leave a comment and I'll amend the answer.如果有人发现其他情况,请发表评论,我会修改答案。 Here's what I tried:这是我尝试过的:

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()
    }
}

I had (and now have) the same issue as you describe.我有(现在有)和你描述的一样的问题。 When dragging, the corners of my items are not rounded anymore and the items in general are cut off (as if i would have called clipped() on them).拖动时,我的项目的角不再是圆形的,并且一般项目被切断(好像我会在它们上调用clipped() )。 My workaround up untill iOS 15 was to remove the preview:iOS 15之前,我的解决方法是删除预览:

.onDrag({
    current = item
    return NSItemProvider(object: "\(item.id)" as NSString)
 }, preview: {
    Text(" ") // replace eventually ...
 })

The empty text view here works better than an EmptyView() , as it fully removes any preview (instead of a small indicator).此处的空文本视图比EmptyView()效果更好,因为它完全删除了任何预览(而不是小指示器)。

However, with iOS 16 , this solution does not work anymore (they added some initial drag animation) and even displays a warning ( CLIENT APP ERROR - Neither the view or container of the UITargetedPreview is currently in a window. This is in violation of UIDragInteraction API contract and can cause a severe visual glich. THIS IS A CLIENT APP BUG and will soon be a hard assert. PLEASE FIX ME ).但是,对于iOS 16 ,此解决方案不再起作用(他们添加了一些初始拖动动画),甚至显示警告( CLIENT APP ERROR - Neither the view or container of the UITargetedPreview is currently in a window. This is in violation of UIDragInteraction API contract and can cause a severe visual glich. THIS IS A CLIENT APP BUG and will soon be a hard assert. PLEASE FIX ME )。

Therefore, did you find any solution yet?因此,您找到任何解决方案了吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM