Sil ve "Diğer" düğmesini hızlıca kaydırın (iOS 7'deki Posta uygulamasında olduğu gibi)


246

Kullanıcı tablo görünümünde bir hücreyi kaydırdığında "daha fazla" düğmesi nasıl oluşturulur (ios 7'deki posta uygulaması gibi)

Bu bilgiyi hem burada hem de Cocoa Touch forumunda arıyordum, ancak cevabı bulamıyorum ve kendimden daha akıllı birisinin bana bir çözüm sunabileceğini umuyorum.

Kullanıcı bir tablo görünümü hücresini kaydırdığında, birden fazla düzenleme düğmesini görüntülemek için (varsayılan olarak sil düğmesi) isterim. İOS 7 için Mail uygulamasında silmek için hızlıca kaydırabilirsiniz, ancak görünen bir "DAHA FAZLA" düğmesi vardır.

resim açıklamasını buraya girin



"Sil" düğmesini eklemek için aşağıdaki iki işlevi uygularım. - (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath; - (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editingStyle forRowAtIndexPath: (NSIndexPath *) indexPath; Ve yanına "Diğer" düğmesini eklemek istiyorum.
Guy Kahlon

3
@MonishBansal Bansal Bu konudaki birisine benziyor ( devforums.apple.com/message/860459#860459 Apple geliştirici forumunda) devam etti ve kendi uygulamalarını oluşturdu. GitHub'da istediğinizi yapan bir proje bulabilirsiniz: github.com/daria-kopaliani/DAContextMenuTableViewController
Guy Kahlon

8
@GuyKahlonMatrix bir cazibe gibi çalıştığı çözüm için teşekkürler. Bu soru birçok google aramasında 1 numaralı sonuçtur ve insanlar yorumları kullanarak bilgilerini paylaşmak zorunda kalırlar, çünkü bir adam soruyu kapatmanın ve demokrasiyi vaaz etmenin daha yararlı olduğuna karar verdi. Burası açıkça daha iyi mods gerekir.
Şafak Gezer

2
İOS 8'i hedefleyebiliyorsanız, aşağıdaki cevabım istediğiniz şey olacaktır.
Johnny

Yanıtlar:


126

Nasıl Uygulanır?

Görünüşe göre iOS 8 bu API'yı açıyor. Bu işlevselliğin ipuçları Beta 2'de bulunmaktadır.

Bir şeyin işe yaramasını sağlamak için, istenen etkiyi elde etmek üzere UITableView temsilcinize aşağıdaki iki yöntemi uygulayın (örnek için özete bakın).

- tableView:editActionsForRowAtIndexPath:
- tableView:commitEditingStyle:forRowAtIndexPath:


Bilinen Sorunlar

Belgelerde tableView: commitEditingStyle: forRowAtIndexPath diyor:

"UITableViewRowAction kullanarak düzenleme eylemleri için çağrılmadı; bunun yerine eylemin işleyicisi çağrılır."

Ancak, kaydırma işlemi onsuz çalışmaz. Yöntem saplaması boş olsa bile, şimdilik buna ihtiyacı var. Bu açıkça beta 2'deki bir hatadır.


Kaynaklar

https://twitter.com/marksands/status/481642991745265664 https://gist.github.com/marksands/76558707f583dbb8f870

Orijinal Yanıt: https://stackoverflow.com/a/24540538/870028


Güncelleme:

Bu çalışma ile örnek kod (Swift'te): http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip

Örnek kod MasterViewController.swift içinde bu kolay takip yöntemi içerir ve sadece bu yöntemle OP ekran görüntüsünde gösterilen davranış elde:

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {

    var moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "More", handler:{action, indexpath in
        println("MORE•ACTION");
    });
    moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);

    var deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Delete", handler:{action, indexpath in
        println("DELETE•ACTION");
    });

    return [deleteRowAction, moreRowAction];
}

1
Bu doğru gibi görünüyor, ancak Xcode 6 GM'de kaydırma hareketi işe yaramıyor gibi görünüyor. EditActions'a, tablo görünümü düzenleme moduna getirilerek erişilebilir. Kaydırmanın işe yaramadığını bilen var mı?
Siegfoult

@Siegfoult (boş bırakılsa bile) tableView uygulamasını denediniz mi: commitEditingStyle: forRowAtIndexPath :?
Johnny

Ben objektif c çalışmıyorum .. Aynı kod ben yazdım. lütfen birkaç ipucu önerin.
Katı Yumuşak

@SolidSoft Bakabileceğim örnek bir projeniz var mı? Bu şekilde daha iyi yardım edebilirim.
Johnny

3
Kendi yorumumu cevaplamak için. tableView.editing = false( NOObjc olarak) çağırırsınız ve hücre "kapanır".
Ben Lachman

121

İOS 8 posta uygulaması gibi çeşitli geçişleri ve genişletilebilir düğmeleri destekleyen değiştirilebilir düğmeleri uygulamak için yeni bir kütüphane oluşturdum.

https://github.com/MortimerGoro/MGSwipeTableCell

Bu kütüphane bir UITableViewCell oluşturmanın tüm farklı yollarıyla uyumludur ve iOS 5, iOS 6, iOS 7 ve iOS 8'de test edilmiştir.

İşte bazı geçişlerin bir örneği:

Sınır geçişi:

Sınır geçişi

Klip geçişi

Klip geçişi

3D Geçişi:

resim açıklamasını buraya girin


1
Harika iş! Animasyonları özelleştirmek için geri aramalar yapmak harika olurdu.
Pacu

1
@MortimerGoro İyi iş adamı. Güzel görünüyor. Android Projemin birinde benzer bir efekt uygulamaya çalışıyorum. Lütfen bunu Android'de nasıl başarabileceğimi söyle?
Nitesh Kumar

iOS 8 + iPad'de, hızlıca kaydırma işlemini gerçekleştiremiyorum.
ScorpionKing2k5

Bu inanılmaz bir kütüphane ve çok iyi olan hala destekliyor olması.
yapılandırma dosyasındaki

@ MortimerGoro, "MGSwipeTableCel" l çerçevesi ile denedim ama sorun benim tablo yeniden yüklemek sonra tokatlamak düğmesi gizli. Bu sorun için herhangi bir çalışma.
Ganesh Guturi

71

Johnny'nin cevabı oy vermek için doğru cevap. Bunu sadece yeni başlayanlara (ve Swift sözdizimini öğrenmeyi reddedenlere) daha net hale getirmek için aşağıdaki objektif-c'ye ekliyorum.

Uitableviewdelegate'i bildirdiğinizden ve aşağıdaki yöntemlere sahip olduğunuzdan emin olun:

 -(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
 UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
    {
        NSLog(@"Action to perform with Button 1");
    }];
    button.backgroundColor = [UIColor greenColor]; //arbitrary color
    UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
                                    {
                                        NSLog(@"Action to perform with Button2!");
                                    }];
    button2.backgroundColor = [UIColor blueColor]; //arbitrary color

    return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:

}
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES; //tableview must be editable or nothing will work...
    }

1
önemli söz etmek canEditRowAtIndexPath
Heckscheibe

Hücreyi kaydırdıktan sonra tabloyu yeniden yüklersem, o kaydırma düğmeleri görünür mü?
Ganesh Guturi

25

Bu (oldukça saçma bir şekilde) özel bir API'dir.

Aşağıdaki iki yöntem özeldir ve UITableView temsilcisine gönderilir:

-(NSString *)tableView:(UITableView *)tableView titleForSwipeAccessoryButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
-(void)tableView:(UITableView *)tableView swipeAccessoryButtonPushedForRowAtIndexPath:(NSIndexPath *)indexPath;

Onlar oldukça açıklayıcıdır.


4
Apple bu özelliği iOS 8 ile açtı. Aşağıdaki Johnny'nin cevabına bakın.
Siegfoult

24

Johnny'nin cevabını iyileştirmek için, bu artık genel API kullanılarak aşağıdaki gibi yapılabilir:

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {

    let moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "More", handler:{action, indexpath in
        print("MORE•ACTION");
    });
    moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);

    let deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Delete", handler:{action, indexpath in
        print("DELETE•ACTION");
    });

    return [deleteRowAction, moreRowAction];
}

17

Umarım elma sana ihtiyacın olanı verene kadar bekleyemezsin değil mi? İşte benim seçeneğim.

Özel bir hücre oluşturun. İçinde iki uiview var

1. upper
2. lower

Alt görünümde, ihtiyacınız olan düğmeleri ekleyin. Eylemlerini tıpkı diğer IBAtions'lar gibi ele alın. animasyon zamanına, stiline ve her şeye karar verebilirsiniz.

şimdi üst görünüme bir uiswipegesture ekleyin ve kaydırma hareketiyle alt görünümünüzü ortaya çıkarın. Bunu daha önce yaptım ve endişelendiğim kadarıyla en basit seçenek.

Umarım yardımcı olur.


7

Standart SDK kullanılarak bu mümkün değildir. Bununla birlikte, Mail.app'deki davranışı aşağı yukarı taklit eden çeşitli 3. taraf çözümleri vardır. Bunlardan bazıları (örn. MCSwipeTableViewCell , DAContextMenuTableViewController , RMSwipeTableViewCell ) hareket tanıtıcıları kullanarak hızlıca kaydırma hareketleri algılar, bazıları (örn. SWTableViewCell ) ikinci UISScrollView öğesini standart UITableViewCellScrollView(özel alt görünüm) altına koyar UITableViewCellve bazıları davranışını değiştirir UITableViewCellScrollView.

En son yaklaşımı seviyorum, çünkü dokunma özelliği en doğal. Özellikle, MSCMoreOptionTableViewCell iyidir. Seçiminiz özel gereksinimlerinize bağlı olarak değişebilir (soldan sağa bir pan gerekip gerekmediği, iOS 6 uyumluluğuna ihtiyacınız olup olmadığı vb.). Ayrıca, bu yaklaşımların çoğunun bir yük getirdiğini unutmayın: Apple alt UITableViewCellgörünüm hiyerarşisinde değişiklik yaparsa gelecekteki bir iOS sürümünde kolayca kırılabilirler .


7

Herhangi bir kütüphane kullanmadan Swift 3 sürüm kodu:

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        tableView.tableFooterView = UIView(frame: CGRect.zero) //Hiding blank cells.
        tableView.separatorInset = UIEdgeInsets.zero
        tableView.dataSource = self
        tableView.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return 4
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)

        return cell
    }

    //Enable cell editing methods.
    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {

        return true
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    }

    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

        let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
            //self.isEditing = false
            print("more button tapped")
        }
        more.backgroundColor = UIColor.lightGray

        let favorite = UITableViewRowAction(style: .normal, title: "Favorite") { action, index in
            //self.isEditing = false
            print("favorite button tapped")
        }
        favorite.backgroundColor = UIColor.orange

        let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
            //self.isEditing = false
            print("share button tapped")
        }
        share.backgroundColor = UIColor.blue

        return [share, favorite, more]
    }

}

6

Kullanıcı hücreyi her kaydırdığında çağrılan UITableViewCellalt sınıf ve alt sınıf yöntemini kullanmanız gerekir willTransitionToState:(UITableViewCellStateMask)state. stateBayraklar Sil düğmesi gösteren olursa haber, ve Diğer düğmesini orada gizlemek / gösterecektir.

Ne yazık ki bu yöntem ne Sil düğmesinin genişliğini ne de animasyon süresini verir. Bu nedenle, daha fazla düğmenin çerçevesini ve animasyon süresini kodunuza gözlemlemeniz ve kodlamanız gerekir (kişisel olarak Apple'ın bu konuda bir şeyler yapması gerektiğini düşünüyorum).


7
"Ben şahsen Apple'ın bu konuda bir şeyler yapması gerektiğini düşünüyorum". Katılıyorum. Onlara zaten bir hata raporu / özellik isteği yazdınız mı?
Tafkadasoh

4

Hızlı programlama için

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
  if editingStyle == UITableViewCellEditingStyle.Delete {
    deleteModelAt(indexPath.row)
    self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
  }
  else if editingStyle == UITableViewCellEditingStyle.Insert {
    println("insert editing action")
  }
}

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
  var archiveAction = UITableViewRowAction(style: .Default, title: "Archive",handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
        // maybe show an action sheet with more options
        self.tableView.setEditing(false, animated: false)
      }
  )
  archiveAction.backgroundColor = UIColor.lightGrayColor()

  var deleteAction = UITableViewRowAction(style: .Normal, title: "Delete",
      handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
        self.deleteModelAt(indexPath.row)
        self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic);
      }
  );
  deleteAction.backgroundColor = UIColor.redColor()

  return [deleteAction, archiveAction]
}

func deleteModelAt(index: Int) {
  //... delete logic for model
}

@bibscy bir düzenleme önerebilirsiniz. Uzun zamandır hızlı kullanmadım, bu yüzden doğru sözdiziminin ne olduğundan emin değilim
Michael Yagudaev

3

BU SİZE YARDIMCI OLABİLİR.

-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
 UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
    {
        NSLog(@"Action to perform with Button 1");
    }];
    button.backgroundColor = [UIColor greenColor]; //arbitrary color
    UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
                                    {
                                        NSLog(@"Action to perform with Button2!");
                                    }];
    button2.backgroundColor = [UIColor blueColor]; //arbitrary color

    return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:

}
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return YES; //tableview must be editable or nothing will work...
    }

3

Uygulamama aynı işlevselliği eklemek istiyordum ve birçok farklı öğreticiden ( en iyi DIY çözümü olan raywenderlich) geçtikten sonra Apple'ın kendi UITableViewRowActionsınıfına sahip olduğunu öğrendim , ki bu çok kullanışlı.

Tableview'ın kazan noktası yöntemini şu şekilde değiştirmeniz gerekir:

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]?  {
    // 1   
    var shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Share" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
    // 2
    let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .ActionSheet)

    let twitterAction = UIAlertAction(title: "Twitter", style: UIAlertActionStyle.Default, handler: nil)
    let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)

    shareMenu.addAction(twitterAction)
    shareMenu.addAction(cancelAction)


    self.presentViewController(shareMenu, animated: true, completion: nil)
    })
    // 3
    var rateAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Rate" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
    // 4
    let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .ActionSheet)

    let appRateAction = UIAlertAction(title: "Rate", style: UIAlertActionStyle.Default, handler: nil)
    let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)

    rateMenu.addAction(appRateAction)
    rateMenu.addAction(cancelAction)


    self.presentViewController(rateMenu, animated: true, completion: nil)
    })
    // 5
    return [shareAction,rateAction]
  }

Sen daha bu öğrenebilirsiniz Bu site . Apple'ın kendi belgeleri , arka plan rengini değiştirmek için gerçekten yararlıdır:

Eylem düğmesinin arka plan rengi.

Beyan HEDEF-C @property (anatomik olmayan, kopya) UIColor * backgroundColor Tartışma Düğmeniz için arka plan rengini belirtmek üzere bu özelliği kullanın. Bu özellik için bir değer belirtmezseniz, UIKit, style özelliğindeki değere göre varsayılan bir renk atar.

Kullanılabilirlik iOS 8.0 ve sonraki sürümlerde kullanılabilir.

Düğmenin yazı tipini değiştirmek istiyorsanız, biraz daha zor. SO hakkında başka bir yazı gördüm . Kodu ve bağlantıyı sağlamak uğruna, burada kullandıkları kod. Düğmenin görünümünü değiştirmeniz gerekir. Tableviewcell'e özel bir referans yapmanız gerekir, aksi takdirde uygulamanın genelinde düğmenin görünümünü değiştirirsiniz (bunu istemedim, ancak belki de bilmiyorum :))

Hedef C:

+ (void)setupDeleteRowActionStyleForUserCell {

    UIFont *font = [UIFont fontWithName:@"AvenirNext-Regular" size:19];

    NSDictionary *attributes = @{NSFontAttributeName: font,
                      NSForegroundColorAttributeName: [UIColor whiteColor]};

    NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString: @"DELETE"
                                                                          attributes: attributes];

    /*
     * We include UIView in the containment hierarchy because there is another button in UserCell that is a direct descendant of UserCell that we don't want this to affect.
     */
    [[UIButton appearanceWhenContainedIn:[UIView class], [UserCell class], nil] setAttributedTitle: attributedTitle
                                                                                          forState: UIControlStateNormal];
}

Swift:

    //create your attributes however you want to
    let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())] as Dictionary!            

   //Add more view controller types in the []
    UIButton.appearanceWhenContainedInInstancesOfClasses([ViewController.self])

Bu, en kolay ve en akışlı çizgili IMHO sürümüdür. Umarım yardımcı olur.

Güncelleme: İşte Swift 3.0 sürümü:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    var shareAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Share", handler: {(action, cellIndexpath) -> Void in
        let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .actionSheet)

        let twitterAction = UIAlertAction(title: "Twitter", style: .default, handler: nil)
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        shareMenu.addAction(twitterAction)
        shareMenu.addAction(cancelAction)


        self.present(shareMenu,animated: true, completion: nil)
    })

    var rateAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Rate" , handler: {(action, cellIndexpath) -> Void in
        // 4
        let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .actionSheet)

        let appRateAction = UIAlertAction(title: "Rate", style: .default, handler: nil)
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)

        rateMenu.addAction(appRateAction)
        rateMenu.addAction(cancelAction)


        self.present(rateMenu, animated: true, completion: nil)
    })
    // 5
    return [shareAction,rateAction]
}

1
Cevabınız için teşekkürler, eminim birçok geliştirici için yardımcı olacaktır. Evet, haklısınız, aslında Apple bu çözümü iOS 8'den sağlıyor. Ancak maalesef bu yerel çözüm tam işlevsellik sağlamaz. Örneğin, Apple'ın Posta uygulamasında Apple'ın mevcut API'sı ile iki taraftan (sol taraftan bir düğme ve sağ taraftan üç) düğmeleriniz var ve her iki tarafa da düğmeler ekleyemezsiniz ve ayrıca geçerli API desteklemez kullanıcı her iki yana uzunca kaydırdığında varsayılan eylem. Şimdilik en iyi çözüm IMHO, açık kaynak kodlu MGSwipeTableCell.
Guy Kahlon

@GuyKahlon evet, sol ve sağ tokatlamak konusunda kesinlikle haklısınız ve daha fazla özelleştirme için MGSwipeTableCell'in en iyisi olduğunu kabul ediyorum. Apple'ın kendisi en sofistike seçenek değil, ancak basit görevler için bunu en doğrudan buldum.
Septronic

@Septronic Lütfen kodunuzu Swift 3 olarak güncelleyebilir misiniz? shareMenu.bir addActionyöntem almaz . Teşekkürler
bibscy

@bibscy Hızlı sürümü ekledim. Özellik için de biraz ihtiyacınız var mı? sharemenu sadece bir UIAlertController, bu yüzden harekete geçmelidir. Deneyin ve herhangi bir şans varsa bana bildirin :)
Septronic

3

Gerçek Swift 3 Cevap

Bu ihtiyacınız olan SADECE işlevdir. Özel eylemler için CanEdit veya CommissionEditingStyle işlevlerine ihtiyacınız yoktur.

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let action1 = UITableViewRowAction(style: .default, title: "Action1", handler: {
        (action, indexPath) in
        print("Action1")
    })
    action1.backgroundColor = UIColor.lightGray
    let action2 = UITableViewRowAction(style: .default, title: "Action2", handler: {
        (action, indexPath) in
        print("Action2")
    })
    return [action1, action2]
}

3

İOS 11'den itibaren bu kullanıma herkese açıktır UITableViewDelegate. İşte bazı örnek kod:

- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
    UIContextualAction *delete = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
                                                                         title:@"DELETE"
                                                                       handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
                                                                           NSLog(@"index path of delete: %@", indexPath);
                                                                           completionHandler(YES);
                                                                       }];

    UIContextualAction *rename = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
                                                                         title:@"RENAME"
                                                                       handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
                                                                           NSLog(@"index path of rename: %@", indexPath);
                                                                           completionHandler(YES);
                                                                       }];

    UISwipeActionsConfiguration *swipeActionConfig = [UISwipeActionsConfiguration configurationWithActions:@[rename, delete]];
    swipeActionConfig.performsFirstActionWithFullSwipe = NO;

    return swipeActionConfig;
}

Ayrıca mevcut:

- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath;

Dokümanlar: https://developer.apple.com/documentation/uikit/uitableviewdelegate/2902367-tableview?language=objc


3

Swift 4 ve iO'lar 11+

@available(iOS 11.0, *)
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {

    let delete = UIContextualAction(style: .destructive, title: "Delete") { _, _, handler in

        handler(true)
        // handle deletion here
    }

    let more = UIContextualAction(style: .normal, title: "More") { _, _, handler in

        handler(true)
        // handle more here
    }

    return UISwipeActionsConfiguration(actions: [delete, more])
}

2

Birden fazla veri göstermek için tableViewCell'i kullandım , bir hücrede sağa sola kaydırdıktan sonra iki düğme gösterecek Onayla ve reddet, iki yöntem var, ilki bir argüman alan ApproveFunc ve diğeri de RejectFunc bir argüman alır.

resim açıklamasını buraya girin

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
        let Approve = UITableViewRowAction(style: .normal, title: "Approve") { action, index in

            self.ApproveFunc(indexPath: indexPath)
        }
        Approve.backgroundColor = .green

        let Reject = UITableViewRowAction(style: .normal, title: "Reject") { action, index in

            self.rejectFunc(indexPath: indexPath)
        }
        Reject.backgroundColor = .red



        return [Reject, Approve]
    }

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    func ApproveFunc(indexPath: IndexPath) {
        print(indexPath.row)
    }
    func rejectFunc(indexPath: IndexPath) {
        print(indexPath.row)
    }

Cevabınıza bir okuyucu tarafından öğrenilebilecek bir açıklama ekleyebilir misiniz?
Nico Haase

Sınırlı ve anında yardım sağlayabilecek bu kod snippet'i için teşekkür ederiz. Bir Doğru bir açıklama ölçüde uzun vadeli değer artıracak göstererek neden bu soruna iyi bir çözüm olduğunu ve diğer benzer sorularla gelecek okuyucularına daha kullanışlı bir hale getirecektir. Yaptığınız varsayımlar dahil bazı açıklamalar eklemek için lütfen yanıtınızı düzenleyin .
Tim Diekmann

1

İşte özel API'leri içermeyen veya kendi sisteminizi oluşturmayan biraz kırılgan bir yol. Apple'ın bunu kırmadığına ve umarım bu birkaç kod satırını değiştirebileceğiniz bir API yayınlayacağına dair bahislerinizi koruyorsunuz.

  1. KVO self.contentView.superview.layer.sublayer. Bunu init içinde yapın. Bu UIScrollView katmanıdır. KVO 'alt görünümlerini' yapamazsınız.
  2. Alt görünümler değiştiğinde, scrollview.subviews içinde silme onay görünümünü bulun. Bu, gözlemlenen geri aramada yapılır.
  3. Bu görünümün boyutunu iki katına çıkarın ve tek alt görünümünün soluna bir UIButton ekleyin. Bu aynı zamanda gözlemlenen geri aramada da yapılır. Silme onay görünümünün tek alt görünümü sil düğmesidir.
  4. (isteğe bağlı) UIButton olayı, bir UITableView bulana kadar self.superview öğesini aramalı ve sonra oluşturduğunuz tableView: commitCustomEditingStyle: forRowAtIndexPath: gibi bir veri kaynağı veya temsilci yöntemini çağırmalıdır. [TableView indexPathForCell: self] kullanarak hücrenin indexPath'ini bulabilirsiniz.

Bu ayrıca, standart tablo görünümü düzenleme temsilci geri çağrılarını uygulamanızı gerektirir.

static char kObserveContext = 0;

@implementation KZTableViewCell {
    UIScrollView *_contentScrollView;
    UIView *_confirmationView;
    UIButton *_editButton;
    UIButton *_deleteButton;
}

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        _contentScrollView = (id)self.contentView.superview;

        [_contentScrollView.layer addObserver:self
             forKeyPath:@"sublayers"
                options:0
                context:&kObserveContext];

        _editButton = [UIButton new];
        _editButton.backgroundColor = [UIColor lightGrayColor];
        [_editButton setTitle:@"Edit" forState:UIControlStateNormal];
        [_editButton addTarget:self
                        action:@selector(_editTap)
              forControlEvents:UIControlEventTouchUpInside];

    }
    return self;
}

-(void)dealloc {
    [_contentScrollView.layer removeObserver:self forKeyPath:@"sublayers" context:&kObserveContext];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if(context != &kObserveContext) {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    }
    if(object == _contentScrollView.layer) {
        for(UIView * view in _contentScrollView.subviews) {
            if([NSStringFromClass(view.class) hasSuffix:@"ConfirmationView"]) {
                _confirmationView = view;
                _deleteButton = [view.subviews objectAtIndex:0];
                CGRect frame = _confirmationView.frame;
                CGRect frame2 = frame;
                frame.origin.x -= frame.size.width;
                frame.size.width *= 2;
                _confirmationView.frame = frame;

                frame2.origin = CGPointZero;
                _editButton.frame = frame2;
                frame2.origin.x += frame2.size.width;
                _deleteButton.frame = frame2;
                [_confirmationView addSubview:_editButton];
                break;
            }
        }
        return;
    }
}

-(void)_editTap {
    UITableView *tv = (id)self.superview;
    while(tv && ![tv isKindOfClass:[UITableView class]]) {
        tv = (id)tv.superview;
    }
    id<UITableViewDelegate> delegate = tv.delegate;
    if([delegate respondsToSelector:@selector(tableView:editTappedForRowWithIndexPath:)]) {
        NSIndexPath *ip = [tv indexPathForCell:self];
        // define this in your own protocol
        [delegate tableView:tv editTappedForRowWithIndexPath:ip];
    }
}
@end

Örnek kod sağlayabilirseniz gerçekten çok mutluyum, Teşekkürler
Guy Kahlon

Bitti. Bir ya da iki hata olabilir, ama özü alırsınız.
xtravar

1

Harika bir kütüphane var, SwipeCellKitdaha fazla onay almalı. Bence bundan daha havalı MGSwipeTableCell. İkincisi, Mail uygulamasının hücrelerinin davranışını tam olarak çoğaltmaz SwipeCellKit. Bir bak


Denedim SwipeCellKitve etkilendim ... Bu istisnalardan birini elde edene kadar tablo görünümü güncellemesinden önceki satır sayısı, güncelleştirme +/- satırlardaki değişiklikten sonra aynı değildi çünkü. Mesele şu ki, veri setimi hiç değiştirmedim. Bu endişe verici değilse, ne olduğunu bilmiyorum. Bu yüzden kullanmaya karşı karar verdim ve sadece yeni UITableViewDelegate yöntemlerini kullandım. Daha fazla özelleştirmeye ihtiyacınız varsa, her zaman geçersiz kılabilirsinizwillBeginEditingRowAt: ....
at nalı7

@ at nalı7 bu garip. SwipeCellKit kullanırken asla herhangi bir istisna çalıştırmadım. Sonuçta bir hücrenin veri kaynağı değişikliklerinden kaynaklanan böyle bir istisna ile ne tür bir ilişkisi olabilir?
Andrey Chernukha

1

Hızlı 4

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, sourceView, completionHandler) in
        print("index path of delete: \(indexPath)")
        completionHandler(true)
    }
    let rename = UIContextualAction(style: .normal, title: "Edit") { (action, sourceView, completionHandler) in
        print("index path of edit: \(indexPath)")
        completionHandler(true)
    }
    let swipeActionConfig = UISwipeActionsConfiguration(actions: [rename, delete])
    swipeActionConfig.performsFirstActionWithFullSwipe = false
    return swipeActionConfig
}

Kodlarınızdaki kaynak görünümü nedir? Simge veya Resim mi?
Saeed Rahmatolahi

1
@SaeedRahmatolahi, sourceView" Eylemin görüntülendiği görünümdür." Daha fazla bilgi için "UIContextualAction.Handler" ifadesini arayın.
Mark Moeykens

0

İşte basit bir çözüm. UITableViewCell içinde özel UIView görüntüleyebilir ve gizleyebilir. Görüntüleme mantığı, UITableViewCell, BaseTableViewCell'den genişletilmiş sınıfın içinde bulunur.

BaseTableViewCell.h

#import <UIKit/UIKit.h>

@interface BaseTableViewCell : UITableViewCell

@property(nonatomic,strong)UIView* customView;

-(void)showCustomView;

-(void)hideCustomView;

@end

BaseTableViewCell.M

#import "BaseTableViewCell.h"

@interface BaseTableViewCell()
{
    BOOL _isCustomViewVisible;
}

@end

@implementation BaseTableViewCell

- (void)awakeFromNib {
    // Initialization code
}

-(void)prepareForReuse
{
    self.customView = nil;
    _isCustomViewVisible = NO;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

-(void)showCustomView
{
    if(nil != self.customView)
    {
        if(!_isCustomViewVisible)
        {
            _isCustomViewVisible = YES;

            if(!self.customView.superview)
            {
                CGRect frame = self.customView.frame;
                frame.origin.x = self.contentView.frame.size.width;
                self.customView.frame = frame;
                [self.customView willMoveToSuperview:self.contentView];
                [self.contentView addSubview:self.customView];
                [self.customView didMoveToSuperview];
            }

            __weak BaseTableViewCell* blockSelf = self;
            [UIView animateWithDuration:.5 animations:^(){

                for(UIView* view in blockSelf.contentView.subviews)
                {
                    CGRect frame = view.frame;
                    frame.origin.x = frame.origin.x - blockSelf.customView.frame.size.width;
                    view.frame = frame;
                }
            }];
        }
    }
}

-(void)hideCustomView
{
    if(nil != self.customView)
    {
        if(_isCustomViewVisible)
        {
            __weak BaseTableViewCell* blockSelf = self;
            _isCustomViewVisible = NO;
            [UIView animateWithDuration:.5 animations:^(){
                for(UIView* view in blockSelf.contentView.subviews)
                {
                    CGRect frame = view.frame;
                    frame.origin.x = frame.origin.x + blockSelf.customView.frame.size.width;
                    view.frame = frame;
                }
            }];
        }
    }
}

@end

Bu işlevselliği elde etmek için BaseTableViewCell'den tablo görünüm hücrenizi basitçe genişletin.

Ardından, UITableViewDelegate'i uygulayan Inside UIViewController, sol ve sağ tokatlamaları işlemek için iki hareket tanıyıcı oluşturur.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self.tableView registerNib:[UINib nibWithNibName:CUSTOM_CELL_NIB_NAME bundle:nil] forCellReuseIdentifier:CUSTOM_CELL_ID];

    UISwipeGestureRecognizer* leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleLeftSwipe:)];
    leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.tableView addGestureRecognizer:leftSwipeRecognizer];

    UISwipeGestureRecognizer* rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightSwipe:)];
    rightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
    [self.tableView addGestureRecognizer:rightSwipeRecognizer];
}

Daha sonra iki kaydırma işleyicisi ekleyin

- (void)handleLeftSwipe:(UISwipeGestureRecognizer*)recognizer
{
    CGPoint point = [recognizer locationInView:self.tableView];
    NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];

    UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];

    if([cell respondsToSelector:@selector(showCustomView)])
    {
        [cell performSelector:@selector(showCustomView)];
    }
}

- (void)handleRightSwipe:(UISwipeGestureRecognizer*)recognizer
{
    CGPoint point = [recognizer locationInView:self.tableView];
    NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];

    UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];

    if([cell respondsToSelector:@selector(hideCustomView)])
    {
        [cell performSelector:@selector(hideCustomView)];
    }
}

Şimdi, UITableViewDelegate'in cellForRowAtIndexPath içinde, özel UIView oluşturabilir ve ayıklanan hücreye ekleyebilirsiniz.

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCellTableViewCell* cell = (CustomCellTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"CustomCellTableViewCell" forIndexPath:indexPath];

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"CellCustomView"
                                                      owner:nil
                                                    options:nil];

    CellCustomView* customView = (CellCustomView*)[ nibViews objectAtIndex: 0];

    cell.customView = customView;

    return cell;
}

Tabii ki, özel UIView'in bu şekilde yüklenmesi sadece bu örnek içindir. İstediğiniz gibi yönetin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.