写在前面的:
有时候,我们需要将响应事件的子view视图,超出父view视图的范围。但是在默认情况下,超出去的部分,是无法响应事件的!……
重现效果:

解决方法:
- 扩大父view视图区域(呵呵)
- 重写父view的hitTest(_:with:)方法
对于第一种方法,很多时候是最简单粗暴,但有时我们UI设计确实需要子视图超过父视图的效果,那么就可以尝试用第二种方法!
官方定义:
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event; // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
官方解释:
返回视图层级结构(包括其自身)中,包含指定点的事件接收者最远的子视图。(真晦涩!)
Returns the farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point.
一般会跟另一个方法结合使用:(检测当前事件触发点是否在指定视图里面)
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; // default returns YES if point is in bounds
演示代码:
页面定义部分
//
// HitTestView.swift
// UIKit-basic
//
// Created by Qire_er on 2021/12/1.
//
import UIKit
class HitTestView: UIView {
var button: UIButton! // 定义【按钮】控件
var count: Int = 0 // 定义【点击】数
override init(frame: CGRect) {
super.init(frame: frame)
let rect = frame.insetBy(dx: 40, dy: -30) // 设置收缩量
self.button = UIButton(frame: CGRect(x: 0, y: 0, width: rect.width, height: rect.height)) // 创建【按钮】实例
self.button.setTitle("测试:0", for: .normal) // 定义【按钮】显示文本
self.button.addTarget(self, action: #selector(click), for: .touchUpInside) // 定义【按钮】点击事件处理函数
self.button.backgroundColor = UIColor.blue.withAlphaComponent(0.85) // 设置【按钮】背景色
addSubview(self.button) // 添加【按钮】视图
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
// 定义【点击】事件处理函数
@objc func click() {
self.count += 1 // 更新【点击】数
self.button.setTitle("测试:\(count)", for: .normal) // 更新【按钮】显示文本
}
// 重写 hitTest 方法
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
var view = super.hitTest(point, with: event) // 获取上一级view
let ePoint = self.button.convert(point, from: self) // 将事件触发点point的坐标转换为button自己的坐标
// 检测事件触发点point是否在button的内部
let isInside = self.button.point(inside: ePoint, with: event)
if isInside {
// 如果在button内部
view = self.button // 就将button作为事件的第一响应者
}
return view
}
}
控制器使用部分
//
// HitTestCV.swift
// UIKit-basic
//
// Created by Qire_er on 2021/12/1.
//
import UIKit
class HitTestCV: UIViewController {
var contView: UIView! // 定义【容器】视图
override func viewDidLoad() {
super.viewDidLoad()
let width = UIScreen.main.bounds.width // 定义【屏幕】宽度
let height = UIScreen.main.bounds.height // 定义【屏幕】高度
let contWidth: CGFloat = 200 // 定义【容器】宽度
let contHeight: CGFloat = 60 // 定义【容器】视图
let offsetY: CGFloat = 45 // 定义【容器】Y轴偏移量
self.contView = HitTestView(frame: CGRect(x: (width - contWidth) / 2, y: (height - contHeight) / 2 - offsetY, width: contWidth, height: contHeight))
self.contView.backgroundColor = UIColor.orange // 设置【容器】背景色
self.view.addSubview(self.contView) // 添加【容器】到【主视图】
self.view.backgroundColor = UIColor.white // 设置底色为白色,否则黑区区一片!
}
}
(==完==)
ps: 以上仅代表个人浅见,请大佬们指正!-
网友评论