UITableView 自定义插入动作按钮 onSwipe
Posted
技术标签:
【中文标题】UITableView 自定义插入动作按钮 onSwipe【英文标题】:UITableView Custom Inset Action Button onSwipe 【发布时间】:2018-09-21 07:29:38 【问题描述】:我能够制作一个 UITableViewCell
可滑动显示 UIButton
改编 Ray Wenderlich 的演练 here。
目标是一个全方位插图contentView
,其中onPanLeft
会从右侧拉入具有类似顶部/底部插图的uiButton
。
我已经做到了,但是我很难解决一个问题:
-
如果我开始缓慢地向左拖动,
contentView
会迅速左右来回移动。
初始 contentView 状态,UITableViewCell 容器的前导/尾随填充为 20 pt。
以扩展宽度结束 contentView 状态(黄线是蓝色/灰色子视图应该遇到的位置,蓝色子视图宽度增加 - 已修复)
以下是我的相关代码供参考:
var panStartPoint = CGPoint.zero
var startingRightLayoutConstraintConstant: CGFloat = 20
let kBounceValue: CGFloat = 20.0
func buttonTotalWidth() -> CGFloat
return deleteButton.frame.width
func updateConstraintsIfNeeded(_ animated: Bool, completion: @escaping (_ finished: Bool) -> Void)
var duration: Float = 0
if animated
duration = 0.1
UIView.animate(withDuration: TimeInterval(duration), delay: 0, options: .curveEaseOut, animations:
self.layoutIfNeeded()
, completion: completion)
@objc func panThisCell(_ sender: UIPanGestureRecognizer)
if let cell = sender.view?.superview?.superview as? PostTableViewCell
switch sender.state
case .began:
cell.panStartPoint = sender.translation(in: cell.myContentView)
cell.startingRightLayoutConstraintConstant = cell.contentViewRightConstraint.constant
break
case .changed:
let currentPoint: CGPoint = sender.translation(in: cell.myContentView)
let deltaX: CGFloat = currentPoint.x - cell.panStartPoint.x
var panningLeft = false
if (currentPoint.x < cell.panStartPoint.x) panningLeft = true
if (cell.startingRightLayoutConstraintConstant == 20)
if (!panningLeft)
let constant: CGFloat = max(-deltaX, 20)
if (constant == 20)
resetConstraintContstants(cell, toZero: true, notifyDelegateDidClose: true)
else
cell.contentViewLeftConstraint.constant = 20 - constant
cell.contentViewRightConstraint.constant = 20 + constant
else
let constant: CGFloat = min(-deltaX, cell.buttonTotalWidth())
if (constant == cell.buttonTotalWidth())
setConstraintsToShowAllButtons(cell, true, notifyDelegateDidOpen: true)
else
cell.contentViewLeftConstraint.constant = 20 - constant
cell.contentViewRightConstraint.constant = 20 + constant
else
let adjustment: CGFloat = cell.startingRightLayoutConstraintConstant - deltaX
if (!panningLeft)
let constant: CGFloat = max(adjustment, 20)
if (constant == 20)
resetConstraintContstants(cell, toZero: true, notifyDelegateDidClose: true)
else
cell.contentViewLeftConstraint.constant = 20 - constant
cell.contentViewRightConstraint.constant = 20 + constant
else
let constant: CGFloat = min(adjustment, cell.buttonTotalWidth())
if (constant == cell.buttonTotalWidth())
setConstraintsToShowAllButtons(cell, true, notifyDelegateDidOpen: true)
else
cell.contentViewLeftConstraint.constant = 20 - constant
cell.contentViewRightConstraint.constant = 20 + constant
break
case .ended:
let halfOfButton: CGFloat = cell.deleteButton.frame.width / 2
if cell.contentViewRightConstraint.constant >= halfOfButton
setConstraintsToShowAllButtons(cell, true, notifyDelegateDidOpen: true)
else
resetConstraintContstants(cell, toZero: true, notifyDelegateDidClose: true)
break
case .cancelled:
if cell.startingRightLayoutConstraintConstant == 20
resetConstraintContstants(cell, toZero: true, notifyDelegateDidClose: true)
else
setConstraintsToShowAllButtons(cell, true, notifyDelegateDidOpen: true)
break
default:
break
func setConstraintsToShowAllButtons(_ cell: PostTableViewCell, _ animated: Bool, notifyDelegateDidOpen notifyDelegate: Bool)
if cell.startingRightLayoutConstraintConstant == 20 + cell.buttonTotalWidth() && cell.contentViewRightConstraint.constant == 20 + cell.buttonTotalWidth()
return
cell.contentViewLeftConstraint.constant = 20 - cell.buttonTotalWidth() - cell.kBounceValue
cell.contentViewRightConstraint.constant = 20 + cell.buttonTotalWidth() + cell.kBounceValue
cell.deleteButtonTrailingConstraint.constant = cell.kBounceValue
cell.updateConstraintsIfNeeded(animated) finished in
cell.contentViewLeftConstraint.constant = 20 - cell.buttonTotalWidth()
cell.contentViewRightConstraint.constant = 20 + cell.buttonTotalWidth()
cell.deleteButtonTrailingConstraint.constant = 0
cell.updateConstraintsIfNeeded(animated) finished in
cell.startingRightLayoutConstraintConstant = cell.contentViewRightConstraint.constant
func resetConstraintContstants(_ cell: PostTableViewCell,toZero animated: Bool, notifyDelegateDidClose notifyDelegate: Bool)
if cell.startingRightLayoutConstraintConstant == 20 && cell.contentViewRightConstraint.constant == 20
//Already all the way closed, no bounce necessary
return
cell.contentViewRightConstraint.constant = 20 - cell.kBounceValue
cell.contentViewLeftConstraint.constant = 20 + cell.kBounceValue
cell.deleteButtonTrailingConstraint.constant = -cell.deleteButton.frame.width - cell.kBounceValue
cell.updateConstraintsIfNeeded(animated) finished in
cell.contentViewRightConstraint.constant = 20
cell.contentViewLeftConstraint.constant = 20
cell.deleteButtonTrailingConstraint.constant = -cell.deleteButton.frame.width
cell.updateConstraintsIfNeeded(animated) finished in
cell.startingRightLayoutConstraintConstant = cell.contentViewRightConstraint.constant
【问题讨论】:
【参考方案1】:您可以尝试使用您的图片,如下所示。
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]?
let moreClosure = (action: UITableViewRowAction!, indexPath: NSIndexPath!) -> Void in
println("More closure called")
let moreAction = UITableViewRowAction(style: .Normal, title: " ", handler: moreClosure)
if let image = UIImage(named: "image.png")
moreAction.backgroundColor = UIColor(patternImage: image)
return [moreAction]
它在我的应用程序中运行良好。
【讨论】:
我知道这个实现是可用的,但它是否允许“moreAction”按钮具有 uitableview 的顶部/底部插入和角半径?【参考方案2】:我在几年前写了问题中引用的原始教程,ios 7 出来后不久。
老实说,我真的建议现在使用 tableView(_:editActionsForRowAt:)
或 tableView(_:trailingSwipeActionsConfigurationForRowAt:)
UITableViewDelegate
方法。它们得到了官方支持,并且方式比我在那里尝试破解的更简单。
第一个是 iOS 8 及更高版本,第二个是 iOS 11 及更高版本。我还怀疑,自从编写该教程以来,他们可能已经更改了单元的一些底层架构..
【讨论】:
以上是关于UITableView 自定义插入动作按钮 onSwipe的主要内容,如果未能解决你的问题,请参考以下文章
如何使用文本字段 UITableView 从自定义单元格中获取值?
将 UISearchBar 放在自定义 UITableview 中会导致奇怪的动画