Home > Net >  TableView custom swipe action - Rxswift
TableView custom swipe action - Rxswift

Time:11-05

Here is how i use RxSwift in my code:

My news variable in ViewModel:

var news = PublishSubject<[Article]>()

Extensions for using Rxswift with tableview.

extension HomeViewController {
func designTableView() {
    newsTable.separatorStyle = .none
    newsTable.showsVerticalScrollIndicator = false
}

func createCellView() {
    homeViewModel.news.bind(to: newsTable.rx.items(cellIdentifier: "cell", cellType: NewsCell.self)) { _, news, cell in

        cell.newsTitle.text = news.title
        cell.newsImage?.sd_setImage(with: URL(string: news.urlToImage ?? ""), placeholderImage: UIImage(systemName: "photo"))

    }.disposed(by: disposeBag)
}

func whenNewsSelected() {
    newsTable.rx.modelSelected(Article.self).bind { article in
        let vc = self.storyboard?.instantiateViewController(withIdentifier: "NewsDetail") as? NewsDetails
        vc?.article = article
        self.navigationController?.pushViewController(vc!, animated: true)
    }.disposed(by: disposeBag)
}

func setDelegateForTableView() {
    newsTable.rx.setDelegate(self).disposed(by: disposeBag)
}

}

What I want to do is, adding a Favorite action to cell. I tried the code belove but I don't how can I access the news data on that row.

func tableView(_ tableView: UITableView,
               trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
    let FlagAction = UIContextualAction(style: .normal, title: "Fav", handler: { (_: UIContextualAction, _: UIView, success: (Bool) -> Void) in
        print("osman")
        success(true)
    })
    FlagAction.backgroundColor = .orange

    return UISwipeActionsConfiguration(actions: [FlagAction])
}

Can someone help me about this?

CodePudding user response:

Instead of var news = PublishSubject<[Article]>() use let news = BehaviorSubject<[Article]>(value: []) (Note: Subjects should always be let constants, never var.)

Then when you need access to the articles, you can do:

let articles = (try? homeViewModel.news.value()) ?? []

I don't normally recommend using Subjects but the alternative here is to write your own DataSource type or use RxDataSources and that may be too deep down the rabbit hole for you.

if you do want to go down the rabbit hole

Bring in RxDataSources or write your own data source and make it a member of your view controller:

let dataSource = MyDataSource<Article, NewsCell>(cellIdentifier: "cell") { _, news, cell in
    cell.newsTitle.text = news.title
    cell.newsImage?.sd_setImage(with: URL(string: news.urlToImage ?? ""), placeholderImage: UIImage(systemName: "photo"))
}

use it like this:

func createCellView() {
    homeViewModel.news
        .bind(to: newsTable.rx.items(dataSource: dataSource))
        .disposed(by: disposeBag)
}

Then you can access the articles like this:

let articles = dataSource.elements

Here's what a basic data source looks like. This does everything the default RxCocoa data source does.

class MyDataSource<Element, Cell>: NSObject, UITableViewDataSource, RxTableViewDataSourceType
where Cell: UITableViewCell {
    private(set) var elements: [Element] = []
    private let cellIdentifier: String
    private let configureCell: (Int, Element, Cell) -> Void

    init(cellIdentifier: String, configureCell: @escaping (Int, Element, Cell) -> Void) {
        self.cellIdentifier = cellIdentifier
        self.configureCell = configureCell
    }

    func tableView(_ tableView: UITableView, observedEvent: RxSwift.Event<[Element]>) {
        guard case let .next(elements) = observedEvent else { return }
        self.elements = elements
        tableView.reloadData()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        elements.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? Cell else {
            return UITableViewCell()
        }
        let element = elements[indexPath.row]
        configureCell(indexPath.row, element, cell)
        return cell
    }
}
  • Related