How to rotate the Drag&Drop preview in Swift

139 Views Asked by At

I have a problem rotating the preview when I drag a button. In this project I drag a button that represents a street that you can rotate, so when the user rotates the button I save the number of rotations in the button tag. I tried to use the UITargetedDragPreview methods and the drag item's preview provider, but it doesn't work. Is my approach wrong?

This is the code (in the lasts three methods there are the approaches that I tried:

func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
    if let btn=self.cardsStack.hitTest(session.location(in: self.cardsStack), with: nil) as? UIButton{
        let touchedImage=btn.currentBackgroundImage ?? UIImage()
        selectedCard = (touchedImage, btn.tag)
        let itemProvider=NSItemProvider(object: touchedImage)
        let dragItem=UIDragItem(itemProvider: itemProvider)
        selectedBtn=btn
        return [dragItem]
    }
    else{
        return []
    }
}

func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
    return UIDropProposal(operation: .copy)
}

func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
    for dragItem in session.items {
        dragItem.itemProvider.loadObject(ofClass: UIImage.self, completionHandler: {object,error  in
            DispatchQueue.main.async {
                if let btn=self.outerStack.hitTest(session.location(in: self.outerStack), with: nil) as? UIButton{
                    btn.setTitle("", for: .normal)
                    btn.setBackgroundImage(self.selectedCard.0, for: .normal)
                    btn.transform=CGAffineTransform(rotationAngle: (.pi/2)*CGFloat(self.selectedCard.1))
                    let result=self.handler.addCard(at: self.buttonAt(btn: btn)!, to: self.directions(for: self.selectedCard.0, rotations: self.selectedCard.1), in: self.structure(for: self.selectedCard.0), for: self.selectedCard.1)
                    self.selectedCard=(UIImage(),0)
                    self.selectedBtn.transform=CGAffineTransform(rotationAngle: 0)
                    UIView.animate(withDuration: 0.5, animations: {
                        self.selectedBtn.transform=self.selectedBtn.transform.translatedBy(x: 0, y: self.outerStack.frame.maxY)
                    }, completion: {_ in
                        UIView.animate(withDuration: 1, animations: {
                            self.selectedBtn.transform=CGAffineTransform.identity
                            self.selectedBtn.setBackgroundImage(UIImage(named: self.cardsDeck[0]), for: .normal)
                        })
                        self.selectedBtn.tag=0
                        self.cardsDeck.removeFirst()
                    })
                    self.handler.indexActivePlayer = self.handler.indexActivePlayer>=self.handler.players.count-1 ? 0 : self.handler.indexActivePlayer+1
                    let index=self.handler.indexActivePlayer
                    self.turnButton.tintColor=self.handler.players[index].exitColor
                    self.turnButton.title=self.handler.players[index].nickname
                    if let exit = result{
                        self.win=true
                        self.winnerExit=exit
                        self.performSegue(withIdentifier: "result", sender: nil)
                    }
                }
            }
        })
    }
}

func canDrop(for btn:UIButton)->Bool{
    let image=selectedCard.0
    let rotations=selectedCard.1
    let position=buttonAt(btn: btn)!
    if btn.currentBackgroundImage != nil{
        return false
    }
    else{
        let directions=directions(for: image, rotations: rotations)
        var index=0 //punti in cui la strada si può collegare
        var t=false //valore che segnala se è posizionabile in tutte le direzioni in cui c'è qualcosa
        let dir:[Direction]=[.left, .right, .top, .bottom]
        for d in dir{
            switch d {
                case .left:
                    if directions.contains(.left){
                        if handler.streetsTable[position.section][position.row-1].structure[2]>0{
                            t=true
                            index+=1
                        }
                        else if handler.streetsTable[position.section][position.row-1].structure.allSatisfy({$0<0}){
                            index+=1
                        }
                        
                    }
                    else if handler.streetsTable[position.section][position.row-1].structure[2]<0{
                        index+=1 //rileva se la strada a sinistra non è vuota
                    }
                case .top:
                    if directions.contains(.top){
                        if handler.streetsTable[position.section-1][position.row].structure[3]>0{
                            t=true
                            index+=1
                        }
                        else if handler.streetsTable[position.section-1][position.row].structure.allSatisfy({$0<0}){
                            index+=1
                        }
                    }
                    else if handler.streetsTable[position.section-1][position.row].structure[3]<0{
                        index+=1
                    }
                case .right:
                    if directions.contains(.right){
                        if handler.streetsTable[position.section][position.row+1].structure[0]>0{
                            t=true
                            index+=1
                        }
                        else if handler.streetsTable[position.section][position.row+1].structure.allSatisfy({$0<0}){
                            index+=1
                        }
                    }
                    else if handler.streetsTable[position.section][position.row+1].structure[0]<0{
                        index+=1
                    }
                case .bottom:
                    if directions.contains(.bottom){
                        if handler.streetsTable[position.section+1][position.row].structure[1]>0{
                            t=true
                            index+=1
                        }
                        else if handler.streetsTable[position.section+1][position.row].structure.allSatisfy({$0<0}){
                            index+=1
                        }
                    }
                    else if handler.streetsTable[position.section+1][position.row].structure[1]<0{
                        index+=1
                    }
            }
        }
        t=t&&index==4
        return t
    }
}

func dragInteraction(_ interaction: UIDragInteraction, sessionIsRestrictedToDraggingApplication session: UIDragSession) -> Bool {
    return true
}

func dragInteraction(_ interaction: UIDragInteraction, prefersFullSizePreviewsFor session: UIDragSession) -> Bool {
    return false
}

func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
    if let btn=outerStack.hitTest(session.location(in: outerStack), with: nil) as? UIButton{
        return session.canLoadObjects(ofClass: UIImage.self) && canDrop(for: btn)
    }
    else{
        return false
    }
}


func dragInteraction(_ interaction: UIDragInteraction, sessionDidMove session: UIDragSession) {
    session.items[0].previewProvider = {
        let imageView = UIImageView(frame: self.selectedBtn.frame)
        imageView.transform = CGAffineTransform(rotationAngle: .pi/2 * CGFloat(self.selectedCard.1))
        imageView.image=self.selectedCard.0
        return UIDragPreview(view: imageView)
    }
}

func dropInteraction(_ interaction: UIDropInteraction, previewForDropping item: UIDragItem, withDefault defaultPreview: UITargetedDragPreview) -> UITargetedDragPreview? {let parameters=UIPreviewParameters()
parameters.visiblePath=UIBezierPath(rect: selectedBtn.frame)
parameters.shadowPath=UIBezierPath(rect: selectedBtn.frame)
let target=UIPreviewTarget(container: selectedBtn, center: selectedBtn.center, transform: selectedBtn.transform)
return UITargetedDragPreview(view: selectedBtn, parameters: parameters, target: target)
}

func dragInteraction(_ interaction: UIDragInteraction, previewForLifting item: UIDragItem, session: UIDragSession) -> UITargetedDragPreview? {
    let parameters=UIPreviewParameters()
    let w=selectedBtn.frame.width/2
    let h=selectedBtn.frame.height/2
    let x=selectedBtn.frame.midX
    let y=selectedBtn.frame.midY
    parameters.visiblePath=UIBezierPath(rect: CGRect(x: x, y: y, width: w, height: h) )
    selectedBtn.adjustsImageSizeForAccessibilityContentSizeCategory=true
    let target=UIPreviewTarget(container: cardsStack, center: selectedBtn.center)
    return UITargetedDragPreview(view: selectedBtn, parameters: parameters, target: target)
}
0

There are 0 best solutions below