wake-up-neo.net

Grundlegendes Drag & Drop in iOS

Ich möchte eine Ansicht haben, in der Fahrzeuge herumfahren, die der Benutzer auch ziehen und ablegen kann. Was ist Ihrer Meinung nach die beste Strategie, um dies zu erreichen? Ist es am besten, Berührungsereignisse aus den Ansichten, die die Fahrzeuge darstellen, oder aus der größeren Ansicht zu erhalten? Gibt es ein einfaches Paradigma, das Sie für Drag & Drop verwendet haben und mit dem Sie zufrieden sind? Was sind die Nachteile verschiedener Strategien?

93
Luke

Angenommen, Sie haben eine UIView-Szene mit einem Hintergrundbild und vielen vehicles, Sie können jedes neue Fahrzeug als UIButton definieren (UIImageView wird wahrscheinlich auch funktionieren):

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];

Dann können Sie das Fahrzeug nach Belieben bewegen, indem Sie auf das Ereignis UIControlEventTouchDragInside reagieren, z.

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

Es ist viel einfacher für ein einzelnes Fahrzeug, seine eigenen Auswirkungen zu bewältigen, verglichen mit der Szene als Ganzes.

126
ohho

Neben der Antwort von ohho habe ich eine ähnliche Implementierung ausprobiert, jedoch ohne das "schnelle" Ziehen und Zentrieren zu ziehen.

Die Tasteninitialisierung ist ...

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];

und Methodenimplementierung:

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

Ich sage nicht, dass dies die perfekte Lösung für die Antwort ist. Trotzdem fand ich dies die einfachste Lösung zum Ziehen.

34
JakubKnejzlik

Ich hatte einen Fall, in dem ich Uiviews zwischen mehreren anderen Uviews ziehen/ablegen möchte. In diesem Fall habe ich die beste Lösung gefunden, um die Schwenkereignisse in einer Superansicht zu verfolgen, die alle Drop-Zonen und alle Ziehgiebelobjekte enthält. Der Hauptgrund dafür, die Ereignis-Listener NICHT zu den tatsächlich gezogenen Ansichten hinzuzufügen, war, dass ich die laufenden Schwenkereignisse verlor, sobald ich die Übersicht für die gezogene Ansicht geändert habe. 

Stattdessen habe ich eine ziemlich generische Drag-Drop-Lösung implementiert, die für einzelne oder mehrere Drop-Zonen verwendet werden kann.

Ich habe ein einfaches Beispiel erstellt, das Sie hier sehen können: Ziehen Sie eine Drop-Uiviews zwischen mehreren anderen Uiviews

Wenn Sie sich für den anderen Weg entscheiden, versuchen Sie, Uicontrol anstelle von Uibutton zu verwenden. Sie deklarieren die addTarget-Methoden und sind viel einfacher zu erweitern.

2
jeyben

Ich würde tatsächlich das Ziehen auf der Fahrzeugansicht selbst, und nicht der großen Ansicht - verfolgen, es sei denn, es gibt einen bestimmten Grund, nein.

In einem Fall erlaube ich dem Benutzer das Platzieren von Elementen durch Ziehen auf dem Bildschirm. In diesem Fall experimentierte ich mit sowohl der Draufsicht als auch der Kindansicht ziehbar. Ich habe festgestellt, dass der Code sauberer ist, wenn Sie der UIView ein paar "ziehbare" Ansichten hinzufügen und festlegen, wie sie gezogen werden können. Ich habe einen einfachen Rückruf an das übergeordnete UIView verwendet, um zu prüfen, ob der neue Standort geeignet ist oder nicht - so konnte ich dies mit Animationen angeben.

Die Draufsicht Spur ziehen, denke ich, ist genauso gut, aber das macht es etwas unordentlich, wenn Sie nicht verschiebbare Ansichten hinzufügen möchten, die immer noch mit dem Benutzer interagieren, z. B. eine Schaltfläche.

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

ohhos Antwort hat für mich gut funktioniert. Falls Sie die Swift 2.x Version benötigen:

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

Für Swift 4 Einfach und bequem. ????

Schritt 1: Verbinden Sie Ihre Schaltfläche vom Storyboard mit dem Ansichts-Controller. Und legen Sie alle grundlegenden AutoLayout-Einschränkungen fest 

 @IBOutlet weak var cameraButton: UIButton!

Schritt 2: Hinzufügen einer Schwenkbewegung für die Schaltfläche In viewDidLoad ()

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

Schritt 3: 

Fügen Sie panGestureHandler hinzu

@objc func panGestureHandler(panGesture recognizer: UIPanGestureRecognizer) {

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

    }

Und jetzt deine Tastenaktion

@IBAction func ButtonAction(_ sender: Any) {

        print("This is button Action")
    }

 enter image description here

Hinzufügen Siehe das Ergebnis ☝️

0
Anup Gupta
0
StevenOjo