Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIDragInteractionDelegate: How to display transparent parts in the drag preview returned by dragInteraction(_:previewForLifting:session:)

I'm building a drag and drop interaction for an iOS app. I want to enable the user to drag and drop images containing transparent parts.

However, the default preview for the dragged contents is a rectangle with an opaque white background that covers my app's background.

When I create a custom preview by implementing the UIDragInteractionDelegate method dragInteraction(_:previewForLifting:session:), as in Apple's code sample Adopting Drag and Drop in a Custom View, the transparency of my source image is still not taken into account, meaning my preview image is still displayed in a rectangle with an opaque white background:

func dragInteraction(_ interaction: UIDragInteraction, previewForLifting item: UIDragItem, session: UIDragSession) -> UITargetedDragPreview? {
    guard let image = item.localObject as? UIImage else { return nil }

    // Scale the preview image view frame to the image's size.
    let frame: CGRect
    if image.size.width > image.size.height {
        let multiplier = imageView.frame.width / image.size.width
        frame = CGRect(x: 0, y: 0, width: imageView.frame.width, height: image.size.height * multiplier)
    } else {
        let multiplier = imageView.frame.height / image.size.height
        frame = CGRect(x: 0, y: 0, width: image.size.width * multiplier, height: imageView.frame.height)
    }

    // Create a new view to display the image as a drag preview.
    let previewImageView = UIImageView(image: image)
    previewImageView.contentMode = .scaleAspectFit
    previewImageView.frame = frame

    /*
         Provide a custom targeted drag preview that lifts from the center
         of imageView. The center is calculated because it needs to be in
         the coordinate system of imageView. Using imageView.center returns
         a point that is in the coordinate system of imageView's superview,
         which is not what is needed here.
     */
    let center = CGPoint(x: imageView.bounds.midX, y: imageView.bounds.midY)
    let target = UIDragPreviewTarget(container: imageView, center: center)
    return UITargetedDragPreview(view: previewImageView, parameters: UIDragPreviewParameters(), target: target)
}

I tried to force the preview not to be opaque, but it did not help:

previewImageView.isOpaque = false

How can I get transparent parts in the lift preview?

like image 429
Pierre F Avatar asked Nov 03 '17 13:11

Pierre F


2 Answers

Overwrite the backgroundColor in the UIDragPreviewParameters, as it defines the color for the background of a drag item preview.

Set it to UIColor.clear which is a color object whose grayscale and alpha values are both 0.0.

let previewParameters = UIDragPreviewParameters()
previewParameters.backgroundColor = UIColor.clear // transparent background
return UITargetedDragPreview(view: previewImageView,
                             parameters: previewParameters,
                             target: target)
like image 170
Pierre F Avatar answered Nov 16 '22 02:11

Pierre F


You can define a UIBezierPath according to your image and set it to previewParameters.visiblePath

Example (Swift 4.2):

let previewParameters = UIDragPreviewParameters()
previewParameters.visiblePath = UIBezierPath(roundedRect: CGRect(x: yourX, y: yourY, width: yourWidth, height: yourHeight), cornerRadius: yourRadius)
//... Use the created previewParameters
like image 36
rahulg Avatar answered Nov 16 '22 01:11

rahulg