我们可以实施
hitTest()
以允许使用视图边界之外的触摸。
但是,我们需要
检查
对于被触摸的景色。
所以,你说你有一个子视图(我称之为
tipView
)包含一个按钮和一个分段控件作为子视图,并且您正在添加
tipView
作为的子视图
UITextView
已定位
外部
文本视图的边界。
例如:
class ToolTipTextView: UITextView {
var tipView: UIView!
var btn: UIButton!
var seg: UISegmentedControl!
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit(){
// we need to see the view outside our bounds
self.clipsToBounds = false
tipView = UIView()
tipView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
btn = UIButton()
btn.setTitle("Tap Me", for: [])
btn.setTitleColor(.white, for: .normal)
btn.setTitleColor(.lightGray, for: .highlighted)
btn.backgroundColor = .systemBlue
seg = UISegmentedControl(items: ["One", "Two", "Three"])
[tipView, btn, seg].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}
tipView.addSubview(btn)
tipView.addSubview(seg)
self.addSubview(tipView)
NSLayoutConstraint.activate([
// button at top of tipView, centerX
btn.topAnchor.constraint(equalTo: tipView.topAnchor, constant: 4.0),
btn.centerXAnchor.constraint(equalTo: tipView.centerXAnchor),
// seg control below button
seg.topAnchor.constraint(equalTo: btn.bottomAnchor, constant: 4.0),
seg.bottomAnchor.constraint(equalTo: tipView.bottomAnchor, constant: -4.0),
seg.leadingAnchor.constraint(equalTo: tipView.leadingAnchor, constant: 4.0),
seg.trailingAnchor.constraint(equalTo: tipView.trailingAnchor, constant: -4.0),
// tipView above self, centerX
tipView.bottomAnchor.constraint(equalTo: self.topAnchor, constant: -4.0),
tipView.centerXAnchor.constraint(equalTo: self.centerXAnchor),
])
// targets for btn and seg
btn.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
seg.addTarget(self, action: #selector(segSelected(_:)), for: .valueChanged)
}
@objc func btnTapped(_ sender: Any?) {
let str = self.text ?? ""
self.text = str + " Button Tapped! "
}
@objc func segSelected(_ sender: Any?) {
guard let ctrl = sender as? UISegmentedControl,
let t = ctrl.titleForSegment(at: ctrl.selectedSegmentIndex)
else { return }
let str = self.text ?? ""
self.text = str + " Segment \(t) Selected! "
}
}
class TipTestVC: UIViewController {
let myView = ToolTipTextView()
override func viewDidLoad() {
super.viewDidLoad()
myView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
myView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
myView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
myView.heightAnchor.constraint(equalToConstant: 160.0),
myView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
myView.font = .systemFont(ofSize: 20.0, weight: .light)
myView.text = "This is text in the text view."
// so we can see the text view frame
myView.backgroundColor = .green
}
}
并且在运行时会是这样的:
假设这接近你想要的。。。
正如您所看到的,您无法点击按钮或分段控件。
因此,我们需要添加
hitTest()
按照我们的习惯
ToolTipTextView
类别:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// convert the touch to the tipView coordinate space
let cvtPoint = self.convert(point, to: tipView)
if btn.frame.contains(cvtPoint) {
return btn
}
if seg.frame.contains(cvtPoint) {
return seg
}
return super.hitTest(point, with: event)
}
因为视图、按钮和seg控件
不
在视图的边界内,点击按钮将产生一个触摸点
相对于文本视图
--点击按钮可能会告诉你这一点:
(167.0, -59.5)
。
因此,我们将该点转换为
tipView
坐标空间,并查看它是否包含在按钮或seg控件的框架中。如果是这样的话,我们就返回这一观点。
如果没有,我们打电话
super
让UIKit处理触摸。。。如果触摸在内部则激活文本视图,或者允许触摸到达屏幕上的某个其他UI元素。