Seret dan Lepas Dasar di iOS


93

Saya ingin melihat ada kendaraan yang berkeliling yang juga bisa diseret dan dijatuhkan oleh pengguna. Menurut Anda, apa strategi skala besar terbaik untuk melakukan ini? Apakah yang terbaik adalah mendapatkan acara sentuhan dari tampilan yang mewakili kendaraan, atau dari tampilan yang lebih besar? Apakah ada paradigma sederhana yang Anda gunakan untuk seret dan lepas yang Anda puas? Apa kekurangan dari strategi yang berbeda?


Jawaban:


126

Asumsikan Anda memiliki UIViewpemandangan dengan gambar latar dan banyak lagi vehicles, Anda dapat mendefinisikan setiap kendaraan baru sebagai UIButton(UIImageView mungkin juga akan berfungsi):

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

Kemudian Anda boleh memindahkan kendaraan kemanapun Anda mau, dengan merespon UIControlEventTouchDragInsidekejadian tersebut, misal:

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

Jauh lebih mudah bagi setiap kendaraan untuk menangani tarikannya sendiri, dibandingkan mengelola pemandangan secara keseluruhan.


Tampak hebat dan sangat sederhana! Saya akan mencoba ini.
Lukas

10
Akankah strategi ini menyebabkan penarikan terhenti jika pengguna menyeret tombol lebih cepat daripada animasi yang diperbarui? Jika jari mereka berada di luar kotak, itu akan berhenti menerima imageMoved: withEvent: panggilan, benar?
Tim

Bagaimana Anda bisa tahu jika gambar berhenti menyeret? Bagaimana Anda tahu jari digerakkan?
ymutlu

ohho - apakah mungkin untuk mengimbangi "pegangan" seret untuk gambar atau tombol sehingga bisa diseret di pojok kanan atas atau pojok kiri atas?
LJ Wilson

ketika saya mencoba mendapatkan pengecualian - [drag_move_textViewController imageTouch: withEvent:]: pemilih tidak dikenal dikirim ke instance 0x4b4b1c0
iosDev

34

Selain jawaban ohho, saya telah mencoba implementasi serupa, tetapi tanpa masalah drag "fast" dan centering to drag.

Inisialisasi tombol adalah ...

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

dan penerapan metode:

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

Saya tidak mengatakan, bahwa ini adalah solusi yang tepat untuk jawabannya. Namun demikian saya menemukan ini solusi termudah untuk menyeret.


2
Dalam kode contoh Anda, Anda mendefinisikan UIControl * control = sender setelah digunakan- haruskah itu tidak didefinisikan sebelumnya?
Peter Johnson

@ PeterJohnson: Sebenarnya tidak masalah dalam kasus ini. Tidak ada penggunaan sebelumnya dari variabel ini sejak baris yang Anda sebutkan :)
JakubKnejzlik

1
Bagaimana dengan CGPoint pPrev = [t beforeLocationInView: control]; CGPoint p = [t locationInView: kontrol]; Kedua baris sebelumnya ini tampaknya merujuk pada "kontrol"?
Peter Johnson

Astaga! Bagaimana saya bisa melewatkan itu? : -O ... Saya sudah mengedit jawabannya.
JakubKnejzlik

saya menambahkan pembuat antarmuka formulir tombol dan saya menggunakan autolayout untuk beberapa login saya menyembunyikan tombol dan menampilkannya lagi ketika saya melakukannya kembali ke tempat semula bagaimana mencegah beviour ini
Amr Angry

2

Saya punya kasus di mana saya ingin menyeret / melepaskan tampilan antara beberapa tampilan lainnya. Dalam hal ini saya menemukan solusi terbaik untuk melacak kejadian pan dalam tampilan super yang berisi semua zona lepas dan semua objek pelana tarik. Alasan utama untuk TIDAK menambahkan event listener ke tampilan yang diseret sebenarnya adalah karena saya kehilangan event pan yang sedang berlangsung segera setelah saya mengubah superview untuk tampilan yang diseret.

Sebagai gantinya saya menerapkan solusi drag drop yang agak umum yang dapat digunakan pada satu atau beberapa zona drop.

Saya telah membuat contoh sederhana yang dapat dilihat di sini: Seret tampilan drop antara beberapa tampilan lainnya

Jika Anda memutuskan untuk menggunakan cara lain, coba gunakan uicontrol sebagai ganti uibutton. Mereka mendeklarasikan metode addTarget dan jauh lebih mudah untuk diperluas - karenanya memberikan status dan perilaku khusus.


1

Saya benar-benar akan melacak menyeret pada tampilan kendaraan itu sendiri, daripada tampilan besar - kecuali ada alasan khusus untuk tidak melakukannya.

Dalam satu kasus di mana saya mengizinkan pengguna untuk menempatkan item dengan menyeretnya di layar. Dalam hal ini saya bereksperimen dengan memiliki tampilan atas dan tampilan anak diseret. Saya menemukan kode itu lebih bersih jika Anda menambahkan beberapa tampilan "yang dapat diseret" ke UIView dan menangani bagaimana mereka dapat diseret. Saya menggunakan panggilan balik sederhana ke induk UIView untuk memeriksa apakah lokasi baru cocok atau tidak - jadi saya bisa menunjukkan dengan animasi.

Memiliki trek tampilan atas yang menyeret saya kira sama baiknya, tetapi itu membuatnya sedikit lebih berantakan jika Anda ingin menambahkan tampilan yang tidak dapat diseret yang masih berinteraksi dengan pengguna, seperti tombol.


1
-(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

jawaban ohho bekerja dengan baik untuk saya. Jika Anda membutuhkan versi cepat 2.x:

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
}


0

Untuk Swift 4 Cara mudah dan termudah. 😛

Langkah 1: Hubungkan Tombol Anda Dari Storyboard Untuk Melihat Controller. Dan Setel semua Batasan Tata Letak Otomatis Dasar

 @IBOutlet weak var cameraButton: UIButton!

Langkah 2: Tambah Pan Gesture untuk tombol Anda Dalam viewDidLoad ()

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

Langkah 3:

Tambahkan panGestureHandler

@objc func panGestureHandler(panGesture recognizer: UIPanGestureRecognizer) {

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

    }

Dan Sekarang Aksi Tombol Anda

@IBAction func ButtonAction(_ sender: Any) {

        print("This is button Action")
    }

masukkan deskripsi gambar di sini

Tambahkan Lihat Hasilnya ☝️

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.