[英]Expand cell when tapped in Swift
我一直在尝试在我的应用程序中实现一项功能,以便当用户在我的表格视图中点击一个单元格时,该单元格向下扩展以显示注释。 我在Objective-C中找到了很多这样的例子,但是我还没有找到Swift的例子。
这个示例似乎很完美: 手风琴表单元格-如何动态扩展/收缩uitableviewcell?
我试图将其翻译为Swift:
var selectedRowIndex = NSIndexPath()
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRowIndex = indexPath
tableView.beginUpdates()
tableView.endUpdates()
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if selectedRowIndex == selectedRowIndex.row && indexPath.row == selectedRowIndex.row {
return 100
}
return 70
}
但是,这似乎会使应用程序崩溃。
有任何想法吗?
编辑:
这是我的cellForRowAtIndexPath代码:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomTransactionTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as CustomTransactionTableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
if tableView == self.searchDisplayController?.searchResultsTableView {
cell.paymentNameLabel.text = (searchResults.objectAtIndex(indexPath.row)) as? String
//println(searchResults.objectAtIndex(indexPath.row))
var indexValue = names.indexOfObject(searchResults.objectAtIndex(indexPath.row))
cell.costLabel.text = (values.objectAtIndex(indexValue)) as? String
cell.dateLabel.text = (dates.objectAtIndex(indexValue)) as? String
if images.objectAtIndex(indexValue) as NSObject == 0 {
cell.paymentArrowImage.hidden = false
cell.creditArrowImage.hidden = true
} else if images.objectAtIndex(indexValue) as NSObject == 1 {
cell.creditArrowImage.hidden = false
cell.paymentArrowImage.hidden = true
}
} else {
cell.paymentNameLabel.text = (names.objectAtIndex(indexPath.row)) as? String
cell.costLabel.text = (values.objectAtIndex(indexPath.row)) as? String
cell.dateLabel.text = (dates.objectAtIndex(indexPath.row)) as? String
if images.objectAtIndex(indexPath.row) as NSObject == 0 {
cell.paymentArrowImage.hidden = false
cell.creditArrowImage.hidden = true
} else if images.objectAtIndex(indexPath.row) as NSObject == 1 {
cell.creditArrowImage.hidden = false
cell.paymentArrowImage.hidden = true
}
}
return cell
}
这是插座设置:
我花了很多时间才能使它生效。 以下是我的解决方法。
PS:@rdelmar代码的问题在于他假设您的表中只有一个section
,因此他只比较indexPath.row
。 如果您有多个部分(或者如果您想稍后再考虑扩展代码),则应比较整个索引,如下所示:
1)您需要一个变量来告诉您选择了哪一行。 我看到您已经这样做了,但是您需要将变量恢复为一致的“未选中”状态(用户关闭所有单元格时)。 我相信最好的方法是通过可选的:
var selectedIndexPath: NSIndexPath? = nil
2)您需要确定用户何时选择一个单元格。 didSelectRowAtIndexPath
是显而易见的选择。 您需要考虑以下三种可能的结果:
对于每种情况,我们都会检查selectedIndexPath是否等于nil(不扩展任何单元格),等于被轻击的行的indexPath(已扩展同一单元格)或与indexPath不同(扩展另一个单元格)。 我们相应地调整selectedIndexPath。 此变量将用于检查每行的正确rowHeight。 您在注释中提到didSelectRowAtIndexPath
“似乎没有被调用”。 您是否正在使用println()并检查控制台以查看是否已调用它? 我在下面的代码中包含了一个。
PS:使用tableView.rowHeight
不能正常工作,因为显然在更新tableView中的所有行之前,Swift仅检查一次rowHeight。
最后但并非最不重要的一点是,我使用reloadRowsAtIndexPath
仅重新加载所需的行。 而且,因为我知道它会重绘表格,在必要时重新布局,甚至为更改添加动画效果。 请注意, [indexPath]
位于方括号之间,因为此方法需要一个NSIndexPath数组:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("didSelectRowAtIndexPath was called")
var cell = tableView.cellForRowAtIndexPath(indexPath) as! MyCustomTableViewCell
switch selectedIndexPath {
case nil:
selectedIndexPath = indexPath
default:
if selectedIndexPath! == indexPath {
selectedIndexPath = nil
} else {
selectedIndexPath = indexPath
}
}
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
3)第三步也是最后一步,Swift需要知道何时将每个值传递到像元高度。 我们在这里使用if / else进行类似的检查。 我知道您可以使代码更短一些,但是我正在键入所有内容,以便其他人也可以轻松理解它:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let smallHeight: CGFloat = 70.0
let expandedHeight: CGFloat = 100.0
let ip = indexPath
if selectedIndexPath != nil {
if ip == selectedIndexPath! {
return expandedHeight
} else {
return smallHeight
}
} else {
return smallHeight
}
}
现在,如果上面的代码不能解决问题,则可能是您的代码问题的一些注释:
var cell:CustomTransactionTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as CustomTransactionTableViewCell
我不知道这是否是问题,但self
不必说,因为您可能会将这段代码放在(Custom)TableViewController中。 另外,如果您正确地强制从出队中强制投射单元,则可以不用指定变量类型,而可以信任Swift的推论。 那个力量铸就了as!
在下面的代码中:
var cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier" forIndexPath: indexPath) as! CustomTransactionTableViewCell
但是,您绝对需要设置该标识符。 转到情节提要,选择具有所需单元格的tableView,作为所需TableViewCell的子类(在您的情况下可能是CustomTransactionTableViewCell
)。 现在,在TableView中选择单元格(检查是否选择了正确的元素。最好通过“编辑器”>“显示文档轮廓”打开文档轮廓)。 选中单元格后,转到右侧的“属性”检查器,然后键入“ Identifier
名称。
您也可以尝试注释掉cell.selectionStyle = UITableViewCellSelectionStyle.None
来检查是否以任何方式阻止了选择(通过这种方式,当单元格被选中时,单元格将改变颜色)。
祝你好运,队友。
if语句中的第一个比较永远不会为真,因为您正在将indexPath与整数进行比较。 您还应该使用表中不能包含的行值来初始化selectedRowIndex变量,例如-1,因此在表首次加载时不会展开任何内容。
var selectedRowIndex: NSIndexPath = NSIndexPath(forRow: -1, inSection: 0)
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex.row {
return 100
}
return 70
}
Swift 4.2 var selectedRowIndex: NSIndexPath = NSIndexPath(row: -1, section: 0)
一种不同的方法是在导航堆栈中推送新的视图控制器,并将过渡用于扩展效果。 好处将是SoC(关注点分离)。 两个模式的示例Swift 2.0项目。
我建议用modyfing高度布局约束来解决这个问题
class ExpandableCell: UITableViewCell {
@IBOutlet weak var img: UIImageView!
@IBOutlet weak var imgHeightConstraint: NSLayoutConstraint!
var isExpanded:Bool = false
{
didSet
{
if !isExpanded {
self.imgHeightConstraint.constant = 0.0
} else {
self.imgHeightConstraint.constant = 128.0
}
}
}
}
然后,在ViewController中:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.estimatedRowHeight = 2.0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.tableFooterView = UIView()
}
// TableView DataSource methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ExpandableCell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCell") as! ExpandableCell
cell.img.image = UIImage(named: indexPath.row.description)
cell.isExpanded = false
return cell
}
// TableView Delegate methods
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell
else { return }
UIView.animate(withDuration: 0.3, animations: {
tableView.beginUpdates()
cell.isExpanded = !cell.isExpanded
tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.top, animated: true)
tableView.endUpdates()
})
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell
else { return }
UIView.animate(withDuration: 0.3, animations: {
tableView.beginUpdates()
cell.isExpanded = false
tableView.endUpdates()
})
}
}
完整的教程在这里
在didSelectRowAtIndexPath
获取索引路径后,只需使用以下方法reloadCellsAtIndexpath
重新加载单元格,并在heightForRowAtIndexPathMethod
检查以下条件
if selectedIndexPath != nil && selectedIndexPath == indexPath {
return yourExpandedCellHieght
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.