iOS面试题:子视图超过父视图部分是否可见,能否响应
目录
1 题目:子视图超出父视图的部分能看到么?超出的部分有什么影响?
1 题目:子视图超出父视图的部分能看到么?超出的部分有什么影响?
子视图超出父视图的部分能看到。但是超出的部分不能响应事件。想让超出的部分响应事件,就该写父视图的hitTest方法。判断触碰区域是否在子视图内,如果在子视图内,则返回子视图。让子视图去响应事件。
在父视图添加如下代码。其思路如下:
- 历父视图的所有子视图
- 判断触发事件的点是否在子视图的bounds内
- 如果在,返回这个子视图
-
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *view = [super hitTest:point withEvent:event]; if (view == nil) { for (UIView *subView in self.subviews) { CGPoint p = [subView convertPoint:point fromView:self]; if (CGRectContainsPoint(subView.bounds, p)) { view = subView; } } } return view; }
2 经典用途:tabbar中间凸起按钮点击。
重写- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event这个方法.该方法返回的view为处理事件最合适的view.说到处理事件最合适的view,要简单的说一下点击事件的处理过程:
- 当触摸事件产生后,系统会将该事件加入到由UIApplication管理的事件队列中
- UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常会把事件首先发给主窗口即KeyWindow去处理.
- KeyWindow会在视图层次结构中找到一个最合适的视图来处理触摸事件
- 找到合适的视图控件后,就会调用视图控件的touches方法来作事件的具体处理:touchesBegan,touchesMoved,touchedEnded...等
- 这些touches方法默认的做法是将事件顺着响应链条向上传递,将事件交给上一个响应者进行处理,如果父控件不能接受事件, 那么子控件就不能接受事件
-
//方法返回的view为处理事件最合适的view - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *view = [super hitTest:point withEvent:event]; if (!self.isHidden) { //此处一定要做判断!防止因push导致界面也会响应按钮点击事件的bug //转换坐标到中间按钮,生成一个新的点 CGPoint pointInCenterBtn = [self convertPoint:point toView:self.centerBtn]; //判断 如果该点是在中间按钮,那么处理事件最合适的View,就是这个button if ([self.centerBtn pointInside:pointInCenterBtn withEvent:event]) { return self.centerBtn; } return view; } return view; }
3 其他用法:菜单下拉tableview。
下边的UItableView是加在上边的横条上的,也就是是说UitableView的父视图是半透明的横条,很显然子视图UItableView 超出了父视图的范围,这样点击cell的时候根本没有反应。
分析:点击响应是从从底部往上依次传递的,当点击UITableView的时候,由地图这层往上传递的时候,半透明的横条视图没有包含使用者点击的点的坐标,所以没有办法继续传递,解决的思路是跳过横条view直接让tableView响应点击。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *view = [super hitTest:point withEvent:event];
if (view == nil) {
//将坐标由当前视图发送到 指定视图 fromView是无法响应的范围小父视图
CGPoint stationPoint = [_stationTypeChooseView.tableView convertPoint:point fromView:self];
if (CGRectContainsPoint(_stationTypeChooseView.tableView.bounds, stationPoint))
{
view = _stationTypeChooseView.tableView;
}
}
return view;
}