我有一个带有自定义单元格的UITableView。自定义单元格为三个按钮,覆盖了单元格的整个范围。我试图根据用户选择的标签自动滚动tableview。
我尝试使用NotificationCenter,但是在尝试滚动时会崩溃。有没有更优雅的解决方案?
编辑:我的最终目标是让用户单击optionOne,并将其滚动到紧挨着下面的单元格。诀窍是在没有cellForRowAt的情况下执行此操作,因为由于多个按钮,我正在单元格中对其进行处理。
自定义单元格:
@IBOutlet weak var optionOneLabel: UILabel!
@IBOutlet weak var optionTwoLabel: UILabel!
@IBOutlet weak var optionThreeLabel: UILabel!
override func prepareForReuse() {
super.prepareForReuse()
let optionOne = UITapGestureRecognizer(target: self, action: #selector(CustomCell.optionOnePressed(_:)))
optionOneLabel.addGestureRecognizer(optionOne)
let optionTwo = UITapGestureRecognizer(target: self, action: #selector(CustomCell.optionTwoPressed(_:)))
optionTwoLabel.addGestureRecognizer(optionTwo)
let optionThree = UITapGestureRecognizer(target: self, action: #selector(CustomCell.optionThreePressed(_:)))
optionThreeLabel.addGestureRecognizer(optionThree)
}
@objc func optionOnePressed(_ sender: UITapGestureRecognizer) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "scrollTableOptionOne"), object: nil)
}
@objc func optionTwoPressed(_ sender: UITapGestureRecognizer) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "scrollTableOptionTwo"), object: nil)
}
@objc func optionThreePressed(_ sender: UITapGestureRecognizer) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "scrollTableOptionthree"), object: nil)
}
TableViewController
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(optionOne), name: NSNotification.Name(rawValue: "scrollTableOptionOne"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(optionTwo), name: NSNotification.Name(rawValue: "scrollTableOptionTwo"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(optionThree), name: NSNotification.Name(rawValue: "scrollTableOptionThree"), object: nil)
}
@objc func optionOne() {
let indexPath = NSIndexPath(item: posts.count, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: UITableViewScrollPosition.init(rawValue: indexPath.row + 2)!, animated: true)
}
@objc func optionTwo() {
print("Don't scroll this one for now")
}
@objc func optionThree() {
print("Don't scroll this one for now")
}
让我知道是否需要更多信息。谢谢。
答案 0 :(得分:2)
除了使用通知,您还可以使用按钮在单元格上设置回调,以便在点击其中一个按钮时,使用关于哪个按钮被点击的信息运行回调,以便视图控制器可以执行其操作需要配合它:
作为您要执行的操作的示例,我创建了一个示例项目,您可以下载并查看该示例项目(Xcode 9.4.1,Swift 4.1),虽然有点混乱,但它可以满足您的需要:{{3 }}
首先,使用按钮来设置单元格以处理回调:
$body = "<html><body>";
$Body .= "<table>";
$Body .= "<thead>";
$Body .= "<tr>";
$Body .= "<th></th>";
...
$Body .= "</tr>";
$Body .= "</thead>";
$Body .= "<tbody>";
foreach($urunler as $urun)
{
$gelen_kod = $urun['urun_kodu'];
$gelen_kod_miktar = $urun['miktar'];
$gelen_toplam_fiyat = $urun['toplam_fiyat'];
$urun_kdv_dahil_fiyati = $urun['KDV_dahil_fiyat'];
$urun_adi = $urun['urun_adi'];
$Body .= "<tr style='border: 1px solid #ddd;'>";
$Body .= "<th scope='row'>1</th>";
$Body .= "<td style='border: 1px solid #ddd;'>$gelen_kod</td>";
$Body .= "<td style='border: 1px solid #ddd;'>$urun_adi</td>";
$Body .= "<td style='border: 1px solid #ddd;'>$gelen_kod_miktar</td>";
$Body .= "<td style='border: 1px solid #ddd;'>ADET</td>";
$Body .= "<td style='border: 1px solid #ddd;'>34.25 TL</td>";
$Body .= "<td style='border: 1px solid #ddd;'>%0</td>";
$Body .= "<td style='border: 1px solid #ddd;'>%5</td>";
$Body .= "<td style='border: 1px solid #ddd;'>$urun_kdv_dahil_fiyati</td>";
$Body .= "</tr>";
}
$Body .= "</tbody>";
$Body .= "</table>";
$Body .= "</body></html>";
$mail->Body = $Body;
$mail->IsHTML(true);
对按钮使用枚举可以使代码比仅用于识别按钮的原始数字更整洁。每个按钮都会调用标识自己的回调。
在表视图控制器中,当您在委托中设置单元格时,会将此回调传递给该单元格:
class SelectionCell: UITableViewCell {
enum Button {
case first
case second
case third
}
var callback: ((Button) -> Void)?
@IBAction func firstButtonSelected(_ sender: UIButton) {
callback?(.first)
}
@IBAction func secondButtonSelected(_ sender: UIButton) {
callback?(.second)
}
@IBAction func thirdButtonSelected(_ sender: UIButton) {
callback?(.third)
}
}
注意,我已经传递了override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let value = values[indexPath.row]
switch value {
case .header:
let cell = tableView.dequeueReusableCell(withIdentifier: "Selection", for: indexPath) as! SelectionCell
cell.callback = handler
return cell
case .value:
let cell = tableView.dequeueReusableCell(withIdentifier: "Display", for: indexPath) as! DisplayCell
cell.configure(with: value)
return cell
}
}
而不是handler
,以便它传递了闭包,而不是运行闭包的结果。是运行闭包的单元。
回调看起来像这样(对于我的示例,您的需求将有所不同) 我使用传递给闭包的按钮标识符来识别我感兴趣的IndexPath并将其滚动到顶部
handler()
正如我已经说过的,您可以查看示例项目以了解其工作原理,但这是重要的步骤。
答案 1 :(得分:1)
使用发送通知的单元格作为发送方对象,而不是nil。在您的单元格中:
NotificationCenter.default.post(
name: NSNotification.Name(rawValue: "scrollTableOptionOne"),
object: self)
更改通知处理程序,以便它可以访问通知。从通知中检索单元格并找到indexPath。
@objc func optionOne(ntf: Notification) {
let cell = ntf.object as! UITableViewCell
if let indexPath = tableView.indexPath(for: cell) {
tableView.scrollToRow(at: indexPath,
at: .bottom, animated: true)
}
}
答案 2 :(得分:1)
我认为这是崩溃的原因。
出于性能原因,您应该仅重置单元格的属性 与内容无关的内容,例如Alpha,编辑和 选择状态。表格视图的委托在 tableView(_:cellForRowAt :)应该始终在重置所有内容时 重用细胞
您可以使用关闭或委托代替通知
答案 3 :(得分:1)
我认为您需要像这样更改代码
let indexPath = IndexPath(row: posts.count - 1, section: 0)
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
这会将您的行滚动到表格视图的顶部。
答案 4 :(得分:1)
ScrollToRow方法有问题。 UITableViewScrollPosition
保留以下值-无,顶部,中间,底部枚举值。
更改行:
tableView.scrollToRow(at: indexPath as IndexPath, at: UITableViewScrollPosition.init(rawValue: indexPath.row + 2)!, animated: true)
收件人:
tableView.scrollToRow(at: indexPath as IndexPath, at: .top, animated: true)
为了跟踪索引路径,请在cellForRow:
cell.tag = indexPath.row
并将通知发布为:
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "scrollTableOptionOne"), object: self.tag)
@objc func optionOne(_ notification: Notification) {
let indexPath = NSIndexPath(item: notification.object+1, section: 0)
tableView.scrollToRow(at: indexPath as IndexPath, at: UITableViewScrollPosition.init(rawValue: indexPath.row + 2)!, animated: true)
}
答案 5 :(得分:1)
更好的方法是使用closures
:
@IBOutlet weak var optionOneLabel: UILabel!
@IBOutlet weak var optionTwoLabel: UILabel!
@IBOutlet weak var optionThreeLabel: UILabel!
var callBackOnLabel : (()->())? /// Add this in cell.
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let optionOne = UITapGestureRecognizer(target: self, action: #selector(CustomCell.optionOnePressed(_:)))
optionOneLabel.addGestureRecognizer(optionOne)
}
@objc func optionOnePressed(_ sender: UITapGestureRecognizer) {
self.callBackOnLabel?()
}
然后在您的cellForRowAt
中:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.callBackOnLabel = {
let selectedIndex = IndexPath(row: posts.count, section: 0)
tableView.scrollToRow(at: selectedIndex, at: .middle, animated: true)
}
}
以相同的方式,您可以为另外两个labels
添加,也可以使其通用以在一次回叫中接受响应并执行动画。