如何把 UITableViewCell/UICollectionViewCell 子视图的触控响应范围拓展到 Cell 之外?

| Swift , iOS , Xcode

 

内容概览

  • 前言
  • 需求描述
  • 遇到的问题
  • 解法
  • 总结

 

前言

 

拓展控件的点击范围是一个比较常见的需求。

然而,如果要把 UITableViewCell/UICollectionViewCell 子视图的触控响应范围拓展到 Cell 之外,你会怎么做呢?

最近,Ficow就遇到了这样的需求。实现的方式其实也比较简单,供你参考哈~

 

需求描述

 

截图里的这些标签,处于一个可滑动的列表中。点击图中红色箭头指向的灰色减号按钮,要触发相应的删除操作。

 

遇到的问题

 

  1. 灰色按钮超出 Cell 的部分,无法响应点击手势;
  2. 超出 Cell bounts 边界的子视图,无法相应点击手势;

读者朋友可以先思考一下,你会怎么解决这两个问题呢?

 

 

解法

 

1. 灰色按钮超出 Cell 的部分,无法响应点击手势;

定义 TouchExpandableButton,然后重写 func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?func point(inside point: CGPoint, with event: UIEvent?) -> Bool 来拓展可点击范围:

import UIKit

final class TouchExpandableButton: UIButton {

    var touchExpandInsets: UIEdgeInsets = .zero

    private var newTouchArea: CGRect {
        CGRect(
            x: bounds.origin.x + touchExpandInsets.left,
            y: bounds.origin.y + touchExpandInsets.top,
            width: bounds.size.width - touchExpandInsets.left - touchExpandInsets.right,
            height: bounds.size.height - touchExpandInsets.top - touchExpandInsets.bottom
        )
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if !self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01 {
            return nil
        }
        if newTouchArea.contains(point) { // 检查触控点是否在拓展后的区域中
            return self
        }
        return nil
    }

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        return newTouchArea.contains(point) // 检查触控点是否在拓展后的区域中
    }
}

 

2. 超出 Cell bounts 边界的子视图,无法相应点击手势;

在 Cell 中重写 func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?

override func hitTest(_ point: CGPoint, with e: UIEvent?) -> UIView? {
    if let result = super.hitTest(point, with:e) {
        return result
    }
    guard let contentView = self.subviews.first else {
        return nil
    }
    let pointInContentView = self.convert(point, to: contentView)
    for subview in contentView.subviews.reversed() {
        let pt = contentView.convert(pointInContentView, to: subview)
        if let hitView = subview.hitTest(pt, with:e) {
            return hitView
        }
    }
    return nil
}

 

总结

 

原理是不是很简单?

核心就是响应链。只要重写 func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?func point(inside point: CGPoint, with event: UIEvent?) -> Bool 来拓展可点击范围,就可以了。

如果还想拓展到 UITableView/ UICollectionView 外面去,也是同样的方法。

 

参考内容:
How can I increase the Tap Area for UIButton?
How can I expand the touchable area of a UICollectionViewCell beyond its bounds?

 

觉得不错?点个赞呗~

本文链接:如何把 UITableViewCell/UICollectionViewCell 子视图的触控响应范围拓展到 Cell 之外?

转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog

评论区(期待你的留言)