如何在按住表格视图单元格时逐渐增加它的大小
How to increase the size of the tableview cell gradually upon holding it
我想做什么(逐字): 在指定的时间内保留一个表格视图单元格。一旦达到该时间段,单元格高度就会逐渐增加。当我松开手指时,单元格高度停止增长。
我有:
我有几个 tableViewCells。使用以下方法在单元格上按指定的时间后:
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: Selector("longPress:"))
longPressRecognizer.minimumPressDuration = 1.0s
longPressRecognizer.delegate = self
self.view.addGestureRecognizer(longPressRecognizer)
我想增加单元格高度。但我无法在不知道触摸位于哪一行的情况下这样做,所以我到了这里:
func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
//let cell = tableView.cellForRow(at: indexPath)
}
}
}
我考虑过控制 rowHeight,但那只是在 tableView 函数中,所以我不知道如何调用它。
我不确定如何进行。 而且我不寻找任何与 .beginUpdates 和 .endUpdates 有关的东西,因为我希望细胞生长是渐进的,最好是动画。
任何帮助将不胜感激,因为我已经为这个特定问题寻找答案很长时间了。
包含 rowHeight 声明的代码:
override func viewDidLoad() {
super.viewDidLoad()
// let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: Selector("longPress:"))
// longPressRecognizer.minimumPressDuration = 1.0 // 1 second press
// longPressRecognizer.delegate = self
// self.view.addGestureRecognizer(longPressRecognizer)
tableView.delegate = self
tableView.dataSource = self
tableView.allowsSelection = false
self.tableView.reorder.delegate = self
view.backgroundColor = UIColor(red:0.64, green:0.93, blue:0.78, alpha:1.0)
tableView.backgroundColor = UIColor.clear
tableView.rowHeight = 84
tableView.rowHeight = UITableViewAutomaticDimension
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
Declare property for height of the cell and return this property in the tableviews's delegate method heightForRowAtIndexPath method
var heightForCell = 100
func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
self. heightForCell = // height you want to set
// now reload cell again
}
}
}
我不喜欢用文字详细解释事情,所以我不会提供冗长的答案,而是包含一个相对较短的代码(也可以作为 gist 使用),其中包含解释基础知识的注释。我并没有真正关注架构和干净的代码,我只是专注于完成任务。照原样使用代码 - 尝试在您的代码库中使其变得更好。
无论如何,代码应该非常清晰且不言自明,但我想在您深入研究之前为您勾勒出一幅大图。在解决方案中,我将高度保存在 CGFloat
(变量 cellHeights
)的数组中,并通过更改数组中的相应高度来修改给定行的高度。该数组作为 heightForRowAt
实施的基础。
当长按开始时,我启动一个计时器,每 0.1 秒通过修改 cellHeights
数组中的高度并告诉 tableView
重绘自身来更新所选行的高度。这种情况会发生,直到达到给定行的限制,然后我才简单地取消(使)计时器。
如果在达到限制高度之前长按结束,我只是明确取消计时器,这样当用户释放按下时单元格停止放大。
就是这样。我建议你拿EnlargingCellsOnLongPressController
gist(或者下面那个,是一样的代码),在你自己的设备上试试看代码和注释,我相信你应该可以根据您自己的情况实施它。
import UIKit
class EnlargingCellsOnLongPressController: UITableViewController {
// this will hold the indexPath of the cell we are currently enlarging
var enlargingIndexPath: IndexPath?
// dummy data model
var modelItems: [String] = []
// we will need to keep the heights for each particular cell (since any can be resized)
var cellHeights: [CGFloat] = []
// some height limit, I will set it for myself to 200
let limitHeight = CGFloat(200)
// the enlarging itself will be done by a timer
weak var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// nothing special here
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.estimatedRowHeight = 100
tableView.allowsSelection = false
// creating some dummy data, 30 items, and for each a cell height that will start at 100
for index in 0..<30 {
modelItems.append("Item \(index)")
// by default we will start with 100
cellHeights.append(CGFloat(100))
}
// please, use swift 4 and the new #selector syntax
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPress(longPressGestureRecognizer:)))
longPressRecognizer.minimumPressDuration = 1
self.view.addGestureRecognizer(longPressRecognizer)
}
// following three methods should be clear
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return modelItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = modelItems[indexPath.row]
return cell
}
// for height for row we will return a specific height from cellHeights array
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return cellHeights[indexPath.row]
}
@objc func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
//when the press starts on a cell, we will keep the indexPath for the cell
self.enlargingIndexPath = indexPath
// and turn on enlarging
self.startEnlarging()
}
} else if longPressGestureRecognizer.state == .ended {
// when the press is ended, we can stop enlarging
stopEnlarging()
}
}
func startEnlarging() {
// interval 0.1 second seems smooth enough (redraw seems to be animated anyway)
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { [weak self] (timer) in
guard let strongSelf = self, let enlargingIndexPath = self?.enlargingIndexPath else { return }
let oldHeight = strongSelf.cellHeights[enlargingIndexPath.row]
// since the timer repeats every 0.1 second, this will enlarge the cell 20 points per second till limit
// in one cycle I will enlarge the cell by two points
let newHeight = oldHeight + 2
if newHeight < strongSelf.limitHeight {
// if the newHeight did not reach limit,
// update height and redraw tableView
strongSelf.cellHeights[enlargingIndexPath.row] = newHeight
strongSelf.tableView.beginUpdates()
strongSelf.tableView.setNeedsLayout()
strongSelf.tableView.endUpdates()
} else {
// reached maximum size, just cancel the timer
strongSelf.stopEnlarging()
}
})
}
func stopEnlarging() {
// this just cancels the timer
timer?.invalidate()
}
}
更新
为了完整起见,我创建了一个使用自动布局的 gist 和 UITableViewAutomaticDimension
,如果您决定使用它而不是 heightForRowAt
。但是原理是一样的。
我想做什么(逐字): 在指定的时间内保留一个表格视图单元格。一旦达到该时间段,单元格高度就会逐渐增加。当我松开手指时,单元格高度停止增长。
我有: 我有几个 tableViewCells。使用以下方法在单元格上按指定的时间后:
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: Selector("longPress:"))
longPressRecognizer.minimumPressDuration = 1.0s
longPressRecognizer.delegate = self
self.view.addGestureRecognizer(longPressRecognizer)
我想增加单元格高度。但我无法在不知道触摸位于哪一行的情况下这样做,所以我到了这里:
func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
//let cell = tableView.cellForRow(at: indexPath)
}
}
}
我考虑过控制 rowHeight,但那只是在 tableView 函数中,所以我不知道如何调用它。
我不确定如何进行。 而且我不寻找任何与 .beginUpdates 和 .endUpdates 有关的东西,因为我希望细胞生长是渐进的,最好是动画。
任何帮助将不胜感激,因为我已经为这个特定问题寻找答案很长时间了。
包含 rowHeight 声明的代码:
override func viewDidLoad() {
super.viewDidLoad()
// let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: Selector("longPress:"))
// longPressRecognizer.minimumPressDuration = 1.0 // 1 second press
// longPressRecognizer.delegate = self
// self.view.addGestureRecognizer(longPressRecognizer)
tableView.delegate = self
tableView.dataSource = self
tableView.allowsSelection = false
self.tableView.reorder.delegate = self
view.backgroundColor = UIColor(red:0.64, green:0.93, blue:0.78, alpha:1.0)
tableView.backgroundColor = UIColor.clear
tableView.rowHeight = 84
tableView.rowHeight = UITableViewAutomaticDimension
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
Declare property for height of the cell and return this property in the tableviews's delegate method heightForRowAtIndexPath method
var heightForCell = 100
func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
self. heightForCell = // height you want to set
// now reload cell again
}
}
}
我不喜欢用文字详细解释事情,所以我不会提供冗长的答案,而是包含一个相对较短的代码(也可以作为 gist 使用),其中包含解释基础知识的注释。我并没有真正关注架构和干净的代码,我只是专注于完成任务。照原样使用代码 - 尝试在您的代码库中使其变得更好。
无论如何,代码应该非常清晰且不言自明,但我想在您深入研究之前为您勾勒出一幅大图。在解决方案中,我将高度保存在 CGFloat
(变量 cellHeights
)的数组中,并通过更改数组中的相应高度来修改给定行的高度。该数组作为 heightForRowAt
实施的基础。
当长按开始时,我启动一个计时器,每 0.1 秒通过修改 cellHeights
数组中的高度并告诉 tableView
重绘自身来更新所选行的高度。这种情况会发生,直到达到给定行的限制,然后我才简单地取消(使)计时器。
如果在达到限制高度之前长按结束,我只是明确取消计时器,这样当用户释放按下时单元格停止放大。
就是这样。我建议你拿EnlargingCellsOnLongPressController
gist(或者下面那个,是一样的代码),在你自己的设备上试试看代码和注释,我相信你应该可以根据您自己的情况实施它。
import UIKit
class EnlargingCellsOnLongPressController: UITableViewController {
// this will hold the indexPath of the cell we are currently enlarging
var enlargingIndexPath: IndexPath?
// dummy data model
var modelItems: [String] = []
// we will need to keep the heights for each particular cell (since any can be resized)
var cellHeights: [CGFloat] = []
// some height limit, I will set it for myself to 200
let limitHeight = CGFloat(200)
// the enlarging itself will be done by a timer
weak var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// nothing special here
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.estimatedRowHeight = 100
tableView.allowsSelection = false
// creating some dummy data, 30 items, and for each a cell height that will start at 100
for index in 0..<30 {
modelItems.append("Item \(index)")
// by default we will start with 100
cellHeights.append(CGFloat(100))
}
// please, use swift 4 and the new #selector syntax
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPress(longPressGestureRecognizer:)))
longPressRecognizer.minimumPressDuration = 1
self.view.addGestureRecognizer(longPressRecognizer)
}
// following three methods should be clear
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return modelItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = modelItems[indexPath.row]
return cell
}
// for height for row we will return a specific height from cellHeights array
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return cellHeights[indexPath.row]
}
@objc func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
//when the press starts on a cell, we will keep the indexPath for the cell
self.enlargingIndexPath = indexPath
// and turn on enlarging
self.startEnlarging()
}
} else if longPressGestureRecognizer.state == .ended {
// when the press is ended, we can stop enlarging
stopEnlarging()
}
}
func startEnlarging() {
// interval 0.1 second seems smooth enough (redraw seems to be animated anyway)
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { [weak self] (timer) in
guard let strongSelf = self, let enlargingIndexPath = self?.enlargingIndexPath else { return }
let oldHeight = strongSelf.cellHeights[enlargingIndexPath.row]
// since the timer repeats every 0.1 second, this will enlarge the cell 20 points per second till limit
// in one cycle I will enlarge the cell by two points
let newHeight = oldHeight + 2
if newHeight < strongSelf.limitHeight {
// if the newHeight did not reach limit,
// update height and redraw tableView
strongSelf.cellHeights[enlargingIndexPath.row] = newHeight
strongSelf.tableView.beginUpdates()
strongSelf.tableView.setNeedsLayout()
strongSelf.tableView.endUpdates()
} else {
// reached maximum size, just cancel the timer
strongSelf.stopEnlarging()
}
})
}
func stopEnlarging() {
// this just cancels the timer
timer?.invalidate()
}
}
更新
为了完整起见,我创建了一个使用自动布局的 gist 和 UITableViewAutomaticDimension
,如果您决定使用它而不是 heightForRowAt
。但是原理是一样的。