web-dev-qa-db-fra.com

Glisser-déposer de base dans iOS

Je veux avoir une vue dans laquelle il y a des véhicules qui circulent et que l'utilisateur peut également glisser-déposer. Quelle est selon vous la meilleure stratégie à grande échelle pour y parvenir? Est-il préférable d’obtenir des événements tactiles à partir des vues représentant les véhicules ou d’une vue plus large? Y a-t-il un paradigme simple que vous avez utilisé pour le glisser-déposer et que vous êtes satisfait? Quels sont les inconvénients des différentes stratégies?

93
Luke

Supposons que vous avez une scène UIView avec une image d’arrière-plan et de nombreux vehicles, vous pouvez définir chaque nouveau véhicule comme une UIButton (UIImageView fonctionnera probablement aussi):

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(imageTouch:withEvent:) forControlEvents:UIControlEventTouchDown];
[button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[button setImage:[UIImage imageNamed:@"vehicle.png"] forState:UIControlStateNormal];
[self.view addSubview:button];

Ensuite, vous pouvez déplacer le véhicule où vous voulez, en répondant à l'événement UIControlEventTouchDragInside, par exemple:

- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
    CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
    UIControl *control = sender;
    control.center = point;
}

Il est beaucoup plus facile pour un véhicule individuel de gérer ses propres traînées, en comparant pour gérer la scène dans son ensemble.

126
ohho

En plus de la réponse de ohho, j'ai essayé une implémentation similaire, mais sans problème de glisser et de centrer "rapidement".

L'initialisation du bouton est ...

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[button addTarget:self action:@selector(imageMoved:withEvent:) forControlEvents:UIControlEventTouchDragOutside];
[button setImage:[UIImage imageNamed:@"vehicle.png"] forState:UIControlStateNormal];
[self.view addSubview:button];

et mise en œuvre de la méthode:

- (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
{
    UIControl *control = sender;

    UITouch *t = [[event allTouches] anyObject];
    CGPoint pPrev = [t previousLocationInView:control];
    CGPoint p = [t locationInView:control];

    CGPoint center = control.center;
    center.x += p.x - pPrev.x;
    center.y += p.y - pPrev.y;
    control.center = center;
}

Je ne dis pas que c'est la solution parfaite pour la réponse. Néanmoins, j’ai trouvé la solution la plus simple pour le glisser.

34
JakubKnejzlik

J'ai eu un cas où je voudrais glisser/déposer des uiviews entre plusieurs autres uiviews. Dans ce cas, j'ai trouvé la meilleure solution pour tracer les événements de panoramique dans une super vue contenant toutes les zones de dépôt et tous les objets pouvant être déplacés. La principale raison pour laquelle nous n'avons PAS ajouté les écouteurs d'événement aux vues déplacées réelles est que j'ai perdu les événements de panoramique en cours dès que j'ai changé de super vue pour la vue déplacée. 

Au lieu de cela, j'ai mis en œuvre une solution de dépôt par glisser-déposer plutôt générique qui pourrait être utilisée sur une ou plusieurs zones de dépôt.

J'ai créé un exemple simple qui peut être vu ici: Faites glisser un drop uiviews entre plusieurs autres uiviews

Si vous décidez d'aller dans l'autre sens, essayez d'utiliser uicontrol au lieu de uibutton. Ils déclarent les méthodes addTarget et sont beaucoup plus faciles à étendre - donnent ainsi un état et un comportement personnalisés.

2
jeyben

En fait, je ferais un suivi en glissant sur la vue vehicle elle-même, plutôt que sur la vue large - à moins d’une raison particulière, non.

Dans un cas où j'autorise l'utilisateur à placer des éléments en les faisant glisser à l'écran. Dans ce cas, j’ai essayé d’avoir les vues top view et child déplaçables. J'ai trouvé que c'est du code plus propre si vous ajoutez quelques vues "déplaçables" à UIView et gérez comment elles peuvent être déplacées. J'ai utilisé un simple rappel au parent UIView pour vérifier si le nouvel emplacement était approprié ou non - afin de pouvoir l'indiquer avec des animations.

Faire glisser la piste top view est tout aussi bon, mais cela la rend un peu plus complexe si vous souhaitez ajouter des vues non déplaçables qui interagissent toujours avec l'utilisateur, comme un bouton.

1
Magnus
-(void)funcAddGesture
{ 

 // DRAG BUTTON
        UIPanGestureRecognizer *panGestureRecognizer;
        panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragButton:)];
        panGestureRecognizer.cancelsTouchesInView = YES;

        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(50, 100, 60, 60);
        [button addTarget:self action:@selector(buttontapEvent) forControlEvents:UIControlEventPrimaryActionTriggered];
        [button setImage:[UIImage imageNamed:@"button_normal.png"] forState:UIControlStateNormal];
        [button addGestureRecognizer:panGestureRecognizer];
        [self.view addSubview:button];
}


- (void)dragButton:(UIPanGestureRecognizer *)recognizer {

    UIButton *button = (UIButton *)recognizer.view;
    CGPoint translation = [recognizer translationInView:button];

    float xPosition = button.center.x;
    float yPosition = button.center.y;
    float buttonCenter = button.frame.size.height/2;

    if (xPosition < buttonCenter)
        xPosition = buttonCenter;
    else if (xPosition > self.view.frame.size.width - buttonCenter)
        xPosition = self.view.frame.size.width - buttonCenter;

    if (yPosition < buttonCenter)
        yPosition = buttonCenter;
    else if (yPosition > self.view.frame.size.height - buttonCenter)
        yPosition = self.view.frame.size.height - buttonCenter;

    button.center = CGPointMake(xPosition + translation.x, yPosition + translation.y);
    [recognizer setTranslation:CGPointZero inView:button];
}


- (void)buttontapEvent {

    NSLog(@"buttontapEvent");
}
1
Balaji G

la réponse de ohho a bien fonctionné pour moi. Si vous avez besoin de la version 2.x de Swift:

override func viewDidLoad() {

    let myButton = UIButton(type: .Custom)
    myButton.setImage(UIImage(named: "vehicle"), forState: .Normal)

    // drag support
    myButton.addTarget(self, action:#selector(imageMoved(_:event:)), forControlEvents:.TouchDragInside)
    myButton.addTarget(self, action:#selector(imageMoved(_:event:)), forControlEvents:.TouchDragOutside)
}

private func imageMoved(sender: AnyObject, event: UIEvent) {
    guard let control = sender as? UIControl else { return }
    guard let touches = event.allTouches() else { return }
    guard let touch = touches.first else { return }

    let prev = touch.previousLocationInView(control)
    let p = touch.locationInView(control)
    var center = control.center
    center.x += p.x - prev.x
    center.y += p.y - prev.y
    control.center = center
}
1
parag

Pour Swift 4 Manière la plus simple et la plus simple. ????

Étape 1: Connectez votre bouton du Storyboard au View Controller. Et définir toutes les contraintes de base de la mise en forme automatique 

 @IBOutlet weak var cameraButton: UIButton!

Étape 2: Ajoutez le geste de panoramique pour votre bouton Dans viewDidLoad ()

self.cameraButton.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGestureHandler(panGesture:))))

Étape 3: 

Ajouter panGestureHandler

@objc func panGestureHandler(panGesture recognizer: UIPanGestureRecognizer) {

         let location = recognizer.location(in: view)
        cameraButton.center = location

    }

Et maintenant votre action de bouton

@IBAction func ButtonAction(_ sender: Any) {

        print("This is button Action")
    }

 enter image description here

Ajouter Voir le résultat

0
Anup Gupta

Voici la meilleure façon de faire glisser et déposer à partir de iOS 11: 

https://developer.Apple.com/documentation/uikit/drag_and_drop/adopting_drag_and_drop_in_a_custom_view

0
StevenOjo