(Swift)如何通过重新加载 UITableView 根据 UITextfield 输入(动画)显示/隐藏单元格?
Posted
技术标签:
【中文标题】(Swift)如何通过重新加载 UITableView 根据 UITextfield 输入(动画)显示/隐藏单元格?【英文标题】:(Swift) How to (animate) show/hide cells based on UITextfield input by reloading a UITableView? 【发布时间】:2016-10-26 10:10:34 【问题描述】:我是一名初级 ios 开发人员,我已经被一个问题困扰了很长一段时间了。
背景:我有一个带有表格视图的视图控制器。它包含 4 个动态原型单元:prototypecell 1 有一个 UITextField 和几个标签,prototypecell 2 有一个图像,prototypecell 3 和 4 只有一个标签。 (注:原型单元格 4 是基于对象中的一个数组,可以有 1 个或多个单元格)
打开屏幕后,只有第一个带有 UITextField 的单元格应该可见。当用户在此 UITextField 中输入一个数字(最多 3 位)时,必须比较该数字以检查它是否是对象数组中的现有数字。如果这个数字被证明是正确的,则必须发生两件事:
-
第一个单元格中的标签需要更改布局(颜色、
字体大小, ...)。第一个单元格更改 rowHeight。
其他 3 个单元格必须出现并显示与数字对应的数据。
如果数字错误,则不会出现多余的单元格,并且第一个单元格会更新以告诉用户它不正确。
问题:我在根据第一个单元格中的数字输入为 3 个单元格出现和消失的方式设置动画时遇到问题。更具体地说,“toggleCellsVisibility”方法以及它与单元格创建的关系。
我尝试了多种组合:beginUpdates()、endUpdates()、reloadData()、reloadRowsAtIndexPath()、DispatchQueue.main.async 和 UIView.Animate()。但是我的代码工作的唯一方法是如果我实现如下的 toggleCellsVisibility 方法,它不会给我任何动画选项。
我似乎在创建和重新加载数据时做错了。我认为这与全局变量 indexOfObject 和 tempObject 的使用有关,它们在屏幕加载时保存虚拟数据,然后在给出正确数字时显示并用实际数据覆盖。
总结:当在第一个单元格中输入正确的数字时,我能否以某种方式插入/创建这 3 个单元格,同时还使用此特定设置为该更改设置动画?
补充: 我可以通过不使用 heightForRowAtIndexPath 来显示/隐藏额外的单元格吗?如果单元格可以自行调整大小会更好。
我选择并简化了相关的代码:
1) TableView 类:
class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, updateUITableView
var objects: [Object] = [
name: "test1", number: "test2", image: "imageName1", color: UIColor.black, array: ["test3", "test4"],
[name: "test1", number: "test2", image: "imageName2", color: UIColor.white, array: ["test3", "test4", "test5"]
//...
]
var cellsRowHeight = false
var indexOfObject: Int = 0
var tempObject = Object[name: "test1", number: "test2", color: UIColor.blue, image: "imageName3", array: ["test3"]]
@IBOutlet var tableView: UITableView!
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int
return 1
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
let numberOfRows = 3 + tempObject.subArray.count
return numberOfRows
//START - Input received from textfield in first cell
func checkNumberInput(senderCell: SearchInputTableViewCell, number: String)
// step 1: Check if number exists
let match = checkNumberMatch(numberInput: number)
// step 2: Change lay-out of input cell
senderCell.changeLayout(numberMatch: match.0, name: match.1?.name, color: match.1?.color)
// step 3: Show/hide cells
toggleCellsVisibility(numberMatch: match.0)
//STEP 1: Check if the number corresponds to an existing number
func checkNumberMatch(numberInput: String) -> (Bool, Object?)
var returnObject: Object?
var tuple = (false, returnObject)
for (index, object) in objects.enumerated() where object.number == numberInput
returnObject = object
tuple = (true, returnObject)
tempObject = object
indexOfObject = index
return tuple
//STEP 3 = !!PROBLEM!!
func toggleCellsVisibility(numberMatch: Bool)
cellsRowHeight = numberMatch
// if/else because of additional future implementation
if numberMatch == true //Cells appear
DispatchQueue.main.async
self.tableView?.reloadData()
else //Cells disappear
DispatchQueue.main.async
self.tableView?.reloadData()
//STEP 4:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
switch (indexPath.row)
case 0 where !cellsRowHeight:
return 187
case 0 where cellsRowHeight:
return 170
case 1 where !cellsRowHeight:
return 0
case 1 where cellsRowHeight:
return 170
case 2 where !cellsRowHeight:
return 0
case 2 where cellsRowHeight:
return 54
case 3...200 where !cellsRowHeight:
return 0
case 3...200 where cellsRowHeight:
return 44
default:
return 44
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
if indexPath.row == 0
let cellIdentifier = "InputCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! InputCell
cell.delegate = self
return cell
else if indexPath.row == 1
let cellIdentifier = "Cell2"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! Cell2
cell.image?.image = UIImage(named: objects[indexOfObject].image)
return cell
else if indexPath.row == 2
let cellIdentifier = "Cell3"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! Cell3
cell.name?.text = objects[indexOfObject].name
return cell
else
let cellIdentifier = "Cell4"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! Cell4
cell.name?.text = objects[indexOfObject].subArray[(indexPath as IndexPath).row - 3]
return cell
2) 细胞类:
protocol updateUITableView: class
func checkNumberInput(senderCell: SearchInputTableViewCell, number: String)
class InputCell: UITableViewCell, UITextFieldDelegate
var delegate: updateUITableView?
@IBOutlet var textField: UITextField!
@IBOutlet var nameLabel: UILabel!
//... and other labels
func changeLayout(numberMatch: Bool, name: String?, color: UIColor?)
if numberMatch == true
//lay-out changes to labels
else
//lay-out changes to labels
//Set maximum character limit in textField and dismiss keyboard when character limit (3) is reached.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let currentCharacterCount = textField.text?.characters.count ?? 0
let newLength = currentCharacterCount + string.characters.count - range.length
if (newLength == 3)
textField.text = (textField.text! as NSString).replacingCharacters(in: range, with: string)
//Get text from textField
let numberInput: String? = textField.text! //Get number if 3 characters entered
if numberInput != nil
delegate?.checkNumberInput(senderCell: self, number: numberInput!)
textField.resignFirstResponder()
if (range.length + range.location > currentCharacterCount)
return false
else
return true
return true
class Cell2: UITableViewCell
@IBOutlet var image: UIImageView!
class Cell3: UITableViewCell
@IBOutlet var name: UILabel!
class Cell4: UITableViewCell
@IBOutlet var name: UILabel!
任何帮助将不胜感激!谢谢!
【问题讨论】:
为什么总是三个单元格?根据需要插入其他单元格(确保 numberOfRowsInSection 始终返回正确的数字) @Paulw11 屏幕始终至少有 1 个单元格(inputCell),但是当输入正确时,会添加额外的 3 个单元格:原型单元格 2 有 1 行带有图像,原型单元格 3 有具有名称和原型单元格的 1 行基于对象中的 subArray 具有未知数量的行。所有这些都必须能够根据输入改变高度。因此 numberOfRowsInSection 将在:1) 1 个单元格 (inputcell) 和 2) 1 个单元格 (inputcell) + 2(两个单元格都有 1 行)+ 基于对象中的子数组的数字之间变化所以我如何能够在对象之间动态切换这些? 【参考方案1】:当您的操作完成后(检查输入是否与您想要的匹配),填充您用于 tableview 的数据源(您应该声明一个要用作数据源的空对象数组,并使用它),然后在您的 tableview 上使用 reloadData()。
对于单元格的高度,您可以使用tableView.rowHeight = UITableViewAutomaticDimension
(https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html)
【讨论】:
以上是关于(Swift)如何通过重新加载 UITableView 根据 UITextfield 输入(动画)显示/隐藏单元格?的主要内容,如果未能解决你的问题,请参考以下文章
如何重新加载 UIPageViewController 以在 Swift 中重新加载其视图
如何重新加载UIPageViewController以在Swift中重新加载其视图
如何使用视图控制器重新加载 tableview (swift)