Ch.9 Gold: Favorite Items

27177 ワード

#お気に入りの表示を許可


  • ある品物を右に一番好きなものと表記する

  • ご褒美として、ボタンなどでお気に入りのもののみ表示しております
  • # tableView(_:leadingSwipeActionsConfigurationForRowAt:)


  • 公式文書を見てみると、この友人はleadingから始まったswifeと知り合い、それに応じた動作をしていた.最初は、swifeアイテムのisfavorite propertyをtrueに変更し、Rows(at:with)メソッドで再ロードするだけでした.

  • そうなると一番好きなアイテムになりますが、本当にちょっと作ったら一番好きなアイテムになります.左側のswifeのように削除されたいので、メソッドを見てみると、戻り値UISWEEActionsConfigurationでswifeアクションを指定できることがわかりました.

  • UIsweeActionsConfigurationは実際に実行するアクションUIconfiguralActionを1つの配列に並べているので、私が望むようにUIconfiguralActionを設定できると思います.設定方法は正直公式文書だけでは理解できないので自分で色々しました

  • UIcontextAction(style:title:handler:UIcontextAction.Handler)を使用して生成し、titleとstyleは初期化時に直ちに設定し、背景色を初期化した後、バックグラウンドプログラムで個別に設定します.
  • 下図の緑色の背景、文字はtitle propertyによって設定された
  • handlerを例にとると、実際にswifeが発生したときにどのような作業をするか、ここでは現在のswife単品のisfavorite propertyを切り替えて再ロードします.このタスクでは、エラー可能なコードがないため、Handlerのcompletion handlerはtrueだけを追加します.道具を探して使うならnilに戻ればtrue/falseの状況を条件文で分かち合えます!
  • class ItemsViewController: UITableViewController {
        ... 
        override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    
            let markAsFavorite = UIContextualAction(style: .normal, title: "Favorite?") { _, _, completionHandler in
                
                let item = self.showOnlyFavaorites ? self.itemStore.favoriteItems[indexPath.row] : self.itemStore.allItems[indexPath.row]
                item.isFavorite.toggle()
                
                if self.showOnlyFavaorites {
                    tableView.reloadData()
                } else {
                    tableView.reloadRows(at: [indexPath], with: .automatic)
                }
                
                completionHandler(true)
            }
    
            markAsFavorite.backgroundColor = .systemGreen
            
            return UISwipeActionsConfiguration(actions: [markAsFavorite])
        }
    }

    #お気に入りのアイテムのみ表示

  • スイッチを追加し、スイッチを切り替えるときに一番好きなものだけを展示します.ItemStoreにFavoriteItems propertyを計算propertyとして追加し、ItemsViewControlにshowOnlyFavorites propertyを追加してスイッチの切り替えステータスを表示します.
  • 大好きなものを展示するだけなら、デリーゲットの様々な方法でItemStoreのall Itemsの代わりにFavoriteItemsを使います.
  • class ItemStore {
        var favoriteItems: [Item] {
            allItems.filter { $0.isFavorite }
        }
    }
    
    class ItemsViewController: UITableViewController {
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            showOnlyFavaorites ? itemStore.favoriteItems.count : itemStore.allItems.count
        }
        
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell", for: indexPath)
            
            let item = showOnlyFavaorites ? itemStore.favoriteItems[indexPath.row] : itemStore.allItems[indexPath.row]
            
            cell.textLabel?.text = item.isFavorite ? "(favorite) \(item.name)": item.name
            cell.detailTextLabel?.text = "$\(item.valueInDollars)"
    
            return cell
        }
        
        private var showOnlyFavaorites = false
        
        @IBAction func showOnlyFavorites(_ sender: UISwitch) {
            showOnlyFavaorites.toggle()
            tableView.reloadData()
        }
    }
  • このとき一番好きなものしか見ていない場合、アイテムを追加、削除、移動すると記録はすべてItemsに記録されるはずですが、indexPathは一番好きなアイテムリストを基準に入ってしまうので問題になります.これにより、indexPathをallItems規格に適切に変換するなどの動作が追加される.
    たとえば、最愛のアイテムリストを表示するときにアイテムを追加する場合、最初に追加するアイテムは通常のアイテムであり、現在のテーブルに追加する必要がないため、insertRows(at:with)メソッドを呼び出す必要はありません.
  • 私は
  • のお気に入りのものしか見ていませんが、物順を変えるとallItemsを基準に順番を変える必要があるのでインデックス変換を行い、ItemStoreにswapItemsAt(:)メソッドを追加しました.
  • class ItemsViewController: UITableViewController {
        
        var itemStore: ItemStore!
        
        @IBAction func addNewItem(_ sender: UIButton) {
            let newItem = itemStore.createItem()
            
            if let index = itemStore.allItems.firstIndex(of: newItem) {
                let indexPath = IndexPath(row: index, section: 0)
                // 모든 아이템을 보고 있을 때만 테이블에 추가
                if !showOnlyFavaorites {
                    tableView.insertRows(at: [indexPath], with: .automatic)
                }
            }
        }
        
        override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
            if editingStyle == .delete {
                let item = showOnlyFavaorites ? itemStore.favoriteItems[indexPath.row] : itemStore.allItems[indexPath.row]
                
                itemStore.removeItem(item)
                
                tableView.deleteRows(at: [indexPath], with: .automatic)
            }
        }
        
        override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
            if showOnlyFavaorites {
                let fromItem = itemStore.favoriteItems[destinationIndexPath.row]
                let toItem = itemStore.favoriteItems[sourceIndexPath.row]
                
                let fromIndex = itemStore.allItems.firstIndex(of: fromItem)!
                let toIndex = itemStore.allItems.firstIndex(of: toItem)!
                
                itemStore.swapItemsAt(fromIndex, toIndex)
            } else {
                itemStore.moveItem(from: sourceIndexPath.row, to: destinationIndexPath.row)
            }
        }
    }
    
    class ItemStore {
        func swapItemsAt(_ fromIndex: Int, _ toIndex: Int) {
            if fromIndex == toIndex {
                return
            }
            
            allItems.swapAt(fromIndex, toIndex)
        }
    }
  • 題の最後の質問は、右端のswifeごとにお気に入りのアイテムを開閉できるようにするためにスイッチキーに変えて、お気に入りのアイテムリストを見てアイテムを削除すると、今ではswifの行(もはやお気に入りのアイテムではない)が消えてしまうので、再ロードする行が消えてアプリが爆発しました.だから私は一番好きな品物のリストを見ています.もし誰かが入ってきたら、READDATA()メソッドを呼び出して表全体を再ロードします.
  • class ItemsViewController: UITableViewController {
        override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    
            let markAsFavorite = UIContextualAction(style: .normal, title: "Favorite?") { _, _, completionHandler in
                
                let item = self.showOnlyFavaorites ? self.itemStore.favoriteItems[indexPath.row] : self.itemStore.allItems[indexPath.row]
                item.isFavorite.toggle()
                
                if self.showOnlyFavaorites { 
                    tableView.reloadData()  // 바로 여기
                } else {
                    tableView.reloadRows(at: [indexPath], with: .automatic)
                }
                
                completionHandler(true)
            }
    
            markAsFavorite.backgroundColor = .systemGreen
            
            return UISwipeActionsConfiguration(actions: [markAsFavorite])
        }
    }