【问题标题】:How to change the title for UITableViewRowAction如何更改 UITableViewRowAction 的标题
【发布时间】:2016-04-23 07:13:08
【问题描述】:

我有一个用例需要更改UITableViewRowAction 的标题。例如,我有一个餐厅单元格,当向右滑动时,我会显示“bookmark(104)”,其中“bookmark”是操作,104 表示已有 104 人为其添加了书签。单击它时,我希望它更改为“书签(105)”,因为显然有一个新用户(当前用户本人)已将其添加为书签。我怎么做?试了下面的代码,还是不行。

let likeAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "bookmark\n\(count)", handler:{(action, indexpath) -> Void in
        ....
        count++
        action.title = "bookmark\n\(count)"
    });

【问题讨论】:

  • 什么是书签(104)? NavigationBar 中的标题?
  • @SaqibOmer 行操作视图中的标题
  • @the_UB 没有更多代码了。我不知道如何编码。
  • @SaqibOmer 我已经稍微编辑了这个问题。
  • 当用户滑动单元格时,它会显示标题为bookmark (104) 的按钮,当他点击它时,单元格会向后滑动隐藏按钮,对吗?所以下次用户滑动时,您仍然看到文本bookmark (104)?你检查过你的 count 属性,看看它在第二次迭代中是否真的有 105 的值?

标签: ios swift


【解决方案1】:

这是一个快速而肮脏的例子。

假设你有一个类 Restaurant 有一个 name 和 likes 值:

class Restaurant {
    var name: String?
    var likes: Int = 0
}

您初始化了一堆Restaurant 对象,并将它们放入一个名为dataSource 的数组中。您的表格视图数据源方法将如下所示:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.dataSource.count
}


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = UITableViewCell(style: .Default, reuseIdentifier: "cell");
    cell.textLabel?.text = dataSource[indexPath.row].name

    return cell
}


// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    // This can be empty if you're not deleting any rows from the table with your edit actions
}

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

    // First, create a share action with the number of likes
    let shareAction = UITableViewRowAction(style: .Default, title: "\(self.dataSource[indexPath.row].likes)") { (action, indexPath) -> Void in

        // In your closure, increment the number of likes for the restaurant, and slide the cell back over
        self.dataSource[indexPath.row].likes++
        self.tableView.setEditing(false, animated: true)
    }

    return [shareAction] // return your array of edit actions for your cell.  In this case, we're only returning one action per row.
}

我不会从头开始编写可滚动单元格,因为this question 有很多可供您使用的选项。

然而,我对 Andrew Carter 尝试遍历子视图以直接在编辑操作中访问 UIButton 很感兴趣。这是我的尝试:

首先,创建一个对UITableViewCell(或单元格数组)的引用,您希望对其进行修改,在此示例中,我将使用单个单元格:

var cellRef: UITableViewCell?

// ...

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = UITableViewCell(style: .Default, reuseIdentifier: "cell");
    cell.textLabel?.text = dataSource[indexPath.row].name

    cellRef = cell;

    return cell
}

在您的分享操作中,遍历按钮的子视图。我们正在寻找 UITableViewCellDeleteConfirmationView_UITableViewCellActionButton 对象(链接以供参考的私有标头)。

let shareAction = UITableViewRowAction(style: .Default, title: "\(self.dataSource[indexPath.row].likes)") { (action, indexPath) -> Void in

    var deleteConfirmationView: UIView? // UITableViewCellDeleteConfirmationView

        if let subviews = self.cellRef?.subviews {
            for subview in subviews {
                if NSClassFromString("UITableViewCellDeleteConfirmationView") != nil {

                    if subview.isKindOfClass(NSClassFromString("UITableViewCellDeleteConfirmationView")!) {
                        deleteConfirmationView = subview
                        break
                    }
                }
            }
        }

    if let unwrappedDeleteView = deleteConfirmationView {
        if unwrappedDeleteView.respondsToSelector("_actionButtons") {
            let actionbuttons = unwrappedDeleteView.valueForKey("_actionButtons") as? [AnyObject]
            if let actionButton = actionbuttons?.first as? UIButton { // _UITableViewCellActionButton
                actionButton.setTitle("newText", forState: .Normal)
            }
        }

    }
}

【讨论】:

  • 这正是我尝试过的方法,但它不起作用。单元格将向后滑动,然后如果您再次向右滑动,您将看到更改。但我希望通过来回滑动来改变它。我想给用户一些即时反馈。
  • @Edmond 如果您使用UITableViewRowAction,您将无法在不重新加载单元格的情况下更改编辑操作的文本。您必须创建自己的自定义滑动视图。
  • 这种方法安全吗? @日航
  • @Edmond App Store 安全吗?当然,您正在遍历子视图并使用 KVO。您没有使用任何私有 API。我已经发布了很多应用程序,我在其中迭代并修改/删除了私有类的子视图。
  • @RaphaelOliveira 使用respondsToSelector 和解包选项使用“更安全”的方法编辑了我的答案。
【解决方案2】:

@JAL 是完全正确的——您需要制作自己的滑动视图来完成此操作,或者可以重新加载单元格并在下一次滑出时更新它。只是为了好玩,我试图破解子视图并找到标签并且能够找到它,但有趣的是Apple以某种方式阻止了对该标签文本进行的任何更改。您可以更改它的背景颜色/其他属性,但不能更改文本!

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
    }

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

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
        return cell
    }

    func findRowActionLabelForCell(cell: UITableViewCell?) -> UILabel? {
        guard let cell = cell else {
            return nil
        }
        var label: UILabel? = nil

        for view in cell.subviews {
            label = findRowActionLabelForView(view)
            if label != nil {
                break
            }
        }

        return label
    }

    func findRowActionLabelForView(view: UIView) -> UILabel? {
        for subview in view.subviews {
            if let label = subview as? UILabel {
                return label
            } else {
                return findRowActionLabelForView(subview)
            }
        }

        return nil
    }

    func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
        let action = UITableViewRowAction(style: .Default, title: "Test", handler: { (action, indexPath) -> Void in

            let cell = self.tableView.cellForRowAtIndexPath(indexPath)
            if let label = self.findRowActionLabelForCell(cell) {
                label.text = "New Value"
                label.backgroundColor = UIColor.blueColor()
            }

        })

        return [action]
    }

    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    }

}

【讨论】:

  • 但是根据我的检查没有UILabel。检查子视图我发现cell!.subviews[0]UITableViewCellDeleteConfirmationViewcell!.subviews[0].subviews[0]_UITableViewCellActionButtoncell!.subviews[0].subviews[0].subviews[0]UIButtonLabel。然而,我们在这里处理的是私有 API,所以这并不重要。我们可能无法控制它。
  • @RaphaelOliveira 很高兴知道这一点。感谢您深入研究!
  • @RaphaelOliveira 不错的尝试。我用一个成功修改了_UITableViewCellActionButtontext 值的版本编辑了我的答案。看看吧。
【解决方案3】:

此答案使用私有 API建议在 App Store 上使用。显然没有办法改变原生UITableViewRowActiontitle。您可能必须按照其他人的建议实施您的自定义解决方案才能达到您想要的结果。

在这里,我正在遍历 UITableViewCell 的子视图,其中包含私有子视图并且可能会发生变化,因此如果 Apple 更改视图层次结构,您的代码可能会在未来的 iOS 版本中崩溃。 我找到了UIButtonLabelhere的标头。

根据 iOS 9.2 的当前视图层次结构是

UITableViewCell
    UITableViewCellDeleteConfirmationView
        _UITableViewCellActionButton
            UIButtonLabel
                UIButton

代码如下:

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let shareAction = UITableViewRowAction(style: .Default, title: "\(dataList[indexPath.row].likes)") { (action, indexPath) -> Void in
        self.dataList[indexPath.row].likes++
        let cell = tableView.cellForRowAtIndexPath(indexPath)
        let privateView = cell!.subviews[0].subviews[0].subviews[0]
        let privateButton = privateView.valueForKey("_button") as! UIButton
        privateButton.setTitle("\(self.dataList[indexPath.row].likes)", forState: .Normal)
    }

    return [shareAction]
} 

【讨论】:

  • 这种方法有潜在的危险。您应该遍历子视图,检查每个子视图的类,而不是假设顺序不会改变。
  • 我知道,这只是一种理论方法,我在回答中表示子视图可能会被修改,可能会导致未来崩溃,不应在 App Store 上使用。
  • 好的。现在我认为这样做的唯一方法是创建一个自定义单元格,将一些按钮作为子视图添加到该单元格,然后向右滑动时,将该按钮移动到屏幕上。这个库也许可以做到这一点。 github.com/torryharris/TH-SwipeCell。你们中的一个人能否总结一个答案,以便我可以将其标记为已接受。
猜你喜欢
  • 2015-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-20
  • 2015-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多