Komórka widoku tabeli z możliwością przesuwania w iOS 9

83

Chcę, aby moja lista tabel miała menu z możliwością przesuwania, jak w iOS 8 (po raz pierwszy wprowadzone w iOS 7).

Zrzut ekranu przycisków akcji w widoku tabeli

Znalazłem przewodnik Raya Wenderlicha, który wyjaśnia, jak to zrobić, ale został napisany rok i 4 miesiące temu, a kod jest w Objective-C.

Czy iOS 8 lub nadchodzący iOS 9 w końcu zawierają tę funkcję w SDK firmy Apple? Wiem, że wiele lat temu wykonali wbudowaną funkcję „przeciągnij, aby odsłonić”. Nie chcę tracić czasu na wdrażanie poprawionego razem kodu, aby naśladować funkcję pocztową iOS 8, jeśli nowy iOS Apple ma mi go przekazać w starannie zapakowanym opakowaniu.

Dave G.
źródło
2
Czy ktoś znalazł rozwiązanie dla przesunięcia od lewej do prawej w Swift? Wydaje się, że prawa do lewej są dobrze udokumentowane i omówione, ale nie od lewej do prawej.
Atticus

Odpowiedzi:

159

Spróbuj tego. (Zaktualizowano dla Swift 3.0) ( Dokumentacja deweloperska )

override func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? {
    let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
        print("more button tapped")
    }
    more.backgroundColor = .lightGray

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

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

    return [share, favorite, more]
}

Zaimplementuj również to: (Możesz ustawić to jako warunkowe, ale tutaj wszystko jest edytowalne)

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

(Starsza wersja)

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
        let more = UITableViewRowAction(style: .Normal, title: "More") { action, index in
            print("more button tapped")
        }
        more.backgroundColor = UIColor.lightGrayColor()

        let favorite = UITableViewRowAction(style: .Normal, title: "Favorite") { action, index in
            print("favorite button tapped")
        }
        favorite.backgroundColor = UIColor.orangeColor()

        let share = UITableViewRowAction(style: .Normal, title: "Share") { action, index in
            print("share button tapped")
        }
        share.backgroundColor = UIColor.blueColor()

        return [share, favorite, more]
    }

    func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // the cells you would like the actions to appear needs to be editable
        return true
    }
jose920405
źródło
11
To nie odpowiada na pytanie. Próbujemy znaleźć wyjście na lewy swipe używając swift To nie robi tego
Somu
Dzięki! To oczywiście nie obsłużyło przesunięcia w lewo w prawo, ale zdecydowałem się zrezygnować z tej funkcji. Jedyne, co nie jest jasne, to jak ustawić automatyczne odświeżanie tabeli po naciśnięciu przycisku, który może przenieść / usunąć komórkę z tabeli?
Dave G
1
Nie wiem, czy masz na myśli tableview.reloadRowsAtIndexPaths ([indexpath] withRowAnimation: UITableViewRowAnimation.Automatic)i do usunięciatableview.deleteRowsAtIndexPaths([indexpath], withRowAnimation: UITableViewRowAnimation.Automatic)
jose920405
2
Czy można otworzyć czynność edycji, dotykając komórki zamiast jej przesuwania?
Heysem Katibi
1
Definicja funkcji Swift 3override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
David Corbin,
28

Ten kod działa dla mnie w wersji swift4.

wprowadź opis obrazu tutaj

Odpowiedź na powyższy ekran to: -

 func tableView(_ tableView: UITableView,
                   trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
    {
        // Write action code for the trash
        let TrashAction = UIContextualAction(style: .normal, title:  "Trash", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
            print("Update action ...")
            success(true)
        })
        TrashAction.backgroundColor = .red

        // Write action code for the Flag
        let FlagAction = UIContextualAction(style: .normal, title:  "Flag", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
            print("Update action ...")
            success(true)
        })
        FlagAction.backgroundColor = .orange

        // Write action code for the More
        let MoreAction = UIContextualAction(style: .normal, title:  "More", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
            print("Update action ...")
            success(true)
        })
        MoreAction.backgroundColor = .gray


        return UISwipeActionsConfiguration(actions: [TrashAction,FlagAction,MoreAction])
    }

wprowadź opis obrazu tutaj

Odpowiedź na powyższy ekran: -

 func tableView(_ tableView: UITableView,
                   leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
    {

        let closeAction = UIContextualAction(style: .normal, title:  "Mark as Read", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
            print("CloseAction ...")
            success(true)
        })
        closeAction.backgroundColor = .blue
        return UISwipeActionsConfiguration(actions: [closeAction])

    }

Napisz metodę delegata widoku tabeli w podobny sposób: -

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return arrPerson.count
    }

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

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let personName = arrPerson[indexPath.row]
        cell.textLabel?.text = personName.personName
        return cell

    }

I w widokuDidLoad

override func viewDidLoad() {
    super.viewDidLoad()

    tblView.delegate = self
    tblView.dataSource = self

    let person1 = personData(personName: "Jonny", personAge: 30)
    let person2 = personData(personName: "Chandan", personAge: 20)
    let person3 = personData(personName: "Gopal", personAge: 28)

   arrPerson.append(person1)
   arrPerson.append(person2)
   arrPerson.append(person3)

}
Niraj Paul
źródło
7
Zajęło to tylko 3 lata :) Dzięki za odpowiedź
Ron Srebro
2
To jest dla iOS 11+
cdub
21

Możesz użyć metody delegata UITableView, aby poprosić o te akcje. Zaimplementuj tę metodę w następujący sposób:

- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
     UITableViewRowAction *modifyAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Modify" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
         // Respond to the action.
     }];
     modifyAction.backgroundColor = [UIColor blueColor];
     return @[modifyAction];
}

Możesz oczywiście zwrócić wiele działań i dostosować tekst i kolor tła.

Zaimplementowanie tej metody jest również wymagane, aby wiersz był edytowalny:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
}
BalestraPatrick
źródło
Czy mogę uzyskać wszystkie te funkcje za pomocą zaledwie kilkunastu wierszy kodu? Albo po prostu mówisz, żeby wstawić kod, którego używam, do tej funkcji. Żaden z podanego kodu nawet nie wygląda tak, jakby modyfikował komórkę. Również próbuję rozwiązać ten problem w Swift.
Dave G
Tak, możesz uzyskać wszystkie funkcjonalności tylko z tym kodem. To wbudowana funkcja. Wow, to jest nawet poprawna odpowiedź i ktoś przegłosował. Jestem zaskoczony.
BalestraPatrick
Należy pamiętać, że jest to dostępne od iOS8 + i pozwala TYLKO przesuwać w lewo, musisz wykonać niestandardową implementację, aby przesuwać w prawo. Poza tym szybka i łatwa odpowiedź
Jiri Trecak
Dziękuję za udostępnienie. Jeśli jestem zbyt niekompetentny, aby zaimplementować pełne menu, mogę skorzystać z tego prostszego rozwiązania. Głosowałem pozytywnie, ponieważ jest istotny, ale nie mogę go wybrać jako odpowiedzi, ponieważ nie odpowiada na pytanie, jak naśladować pełne menu poczty iOS8, a ponadto jest napisane w celu-C.
Dave G
15

Znalazłem tę bibliotekę MGSwipeTableCell Po wielu poszukiwaniach w celu zaimplementowania komórki slajdu w widoku tabeli przy użyciu swift znalazłem tę i jest to tylko jedna linia kodu do wykonania implementacji i uznałem ją za niezwykle użyteczną.

     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
  {
    let reuseIdentifier = "programmaticCell"
    var cell = self.table.dequeueReusableCellWithIdentifier(reuseIdentifier) as! MGSwipeTableCell!
    if cell == nil
    {
      cell = MGSwipeTableCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: reuseIdentifier)
    }

    cell.textLabel!.text = "Title"
    cell.detailTextLabel!.text = "Detail text"
    cell.delegate = self //optional

    //configure left buttons
    cell.leftButtons = [MGSwipeButton(title: "", icon: UIImage(named:"check.png"), backgroundColor: UIColor.greenColor())
      ,MGSwipeButton(title: "", icon: UIImage(named:"fav.png"), backgroundColor: UIColor.blueColor())]
    cell.leftSwipeSettings.transition = MGSwipeTransition.Rotate3D

    //configure right buttons
    cell.rightButtons = [MGSwipeButton(title: "Delete", backgroundColor: UIColor.redColor())
      ,MGSwipeButton(title: "More",backgroundColor: UIColor.lightGrayColor())]
    cell.rightSwipeSettings.transition = MGSwipeTransition.Rotate3D

    return cell
  }

To jedyna funkcja, którą będziesz musiał zaimplementować i zaktualizować plik pod

Somu
źródło
11

Kompletne rozwiązanie Swift 3:

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

}
mriaz0011
źródło
2

AFAIK nie ma wbudowanego gotowego rozwiązania, a nawet jeśli był w iOS9, prawdopodobnie nie możesz go używać, ponieważ nie możesz obsługiwać iOS9 w swojej aplikacji w przewidywalnej przyszłości.

Zamiast tego radzę zajrzeć do tej biblioteki:

https://github.com/CEWendel/SWTableViewCell

Jest bardzo łatwy w konfiguracji, całkiem dopracowany i działał dobrze w każdym szybkim projekcie, nad którym pracowałem.

Mam nadzieję, że to pomoże!

Jiri Trecak
źródło
Dzięki. Nowicjusz w programowaniu i nigdy wcześniej nie używany GitHub. Właśnie pobrałem plik zip i otworzyłem projekt w X-Code, a następnie uruchomiłem projekt, ale otrzymałem komunikat „Build Failed”. Czy muszę scalić kod z moim projektem, zanim będę mógł zobaczyć, jak to działa?
Dave G
Lepiej jest zainstalować Cocoapods jako menedżera zależności; Jest to standard branżowy i pozwoli Ci zaoszczędzić DUŻO bólu głowy. Więcej o cocoapods i jak ich używać tutaj cocoapods.org
Jiri Trecak
Dzięki Jiri, po krótkim przeczytaniu o CocoaPods wygląda na to, że dziś wieczorem będę musiał czytać dalej, aby je zrozumieć. Zrobiłem się chętny i zamiast prowadzić projekt na githubie, po prostu zacząłem przeglądać kod. Jest w celu-C! Moja aplikacja jest w Swift i jest to język, który znam. Czy musiałbym przetłumaczyć rozwiązanie github na Swift, czy też, skoro można je uruchomić obok siebie, byłbym w stanie skopiować kod Objective-C ViewController do mojego BasicCellViewController?
Dave G
Dzięki cocoapods uruchamiasz biblioteki obok siebie, celujesz w C i szybko, jeśli używasz iOS8 +. Następnie możesz bezproblemowo używać kodu Obj-C w swoim szybkim projekcie (ale będzie on ukryty pod projektem „pods”), jedyne co musisz zrobić, to zaimportować bibliotekę objective-c do swojego „Bridging Header” developer.apple.com / library / prerelease / ios / documents / Swift /…
Jiri Trecak
Po prostu przeczytaj o CocoaPods ( raywenderlich.com/97014/use-cocoapods-with-swift ), myślę, że to będzie za dużo dla mojego mózgu. Rozumiem koncepcję, ale wdrażam ją w terminalu, używa obszarów roboczych, uruchamiając moją aplikację na kodzie, który nie jest scalany z innym kodem ... plus dostosowywanie rzeczywistej funkcji menu, aby wyglądała / działała tak, jak chcę ... mój mózg by to zrobił eksplodować. Zamierzam sprawdzić, jak po prostu wkleić ten obj-c i powiedzieć mojej aplikacji, że używam obu języków. Nie robiłem tego wcześniej, ale wydaje się prostsze
Dave G
1

To łatwiejsze niż myślisz. Oto przykład klasy Swift z zaimplementowanym UITableView i możliwością przesuwania UITableViewCell.

import UIKit

class ViewController: UIViewController {

    // MARK: Properties

    let strings = ["firstString", "secondString", "thirdString"]

    // MARK: Outlets

    @IBOutlet weak var tableView: UITableView!

    // MARK: Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self
    }
}

extension ViewController: UITableViewDataSource, UITableViewDelegate {

    // MARK: UITableViewDataSource

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return objects.count
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath)
        let currentString = strings[indexPath.row]
        cell.textLabel?.text = currentString
        return cell
    }

    // MARK: UITableViewDelegate

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }

    func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let leftAction = UIContextualAction(style: .normal, title:  "Red", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
            print("leftAction tapped")
            success(true)
        })

        leftAction.image = UIImage(named: "")
        leftAction.backgroundColor = UIColor.red

        return UISwipeActionsConfiguration(actions: [leftAction])
    }

    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let rightAction = UIContextualAction(style: .normal, title:  "Green", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
            print("rightAction tapped")
            success(true)
        })

        rightAction.image = UIImage(named: "")
        rightAction.backgroundColor = UIColor.green

        return UISwipeActionsConfiguration(actions: [rightAction])
    }

}
iAleksandr
źródło