iOS仿网易新闻滑动菜单开发教程:解决手势冲突,实现丝滑导航
众多iOS开发者,在达成侧滑导航的这个期间,都遭遇过相当繁杂的,和手势冲突相关的状况,这样的情状,确实是直观地,对App的操作流畅程度,以及用户体验造成了影响。
手势冲突的根源
实现仿今日头条的滑动导航时,首要 hurdles 是多个手势识别器间的竞争状况。主视图控制器通常内嵌 UINavigationController,其自身的边缘返回手势即 interactivePopGestureRecognizer 会与自定义的侧滑拖拽手势 panGestureRecognizer 相互干扰。要是不进行处理,那么滑动操作或许无法触发侧滑菜单,或者导致导航栏意外返回。
这种冲突的典型情形是,用户从屏幕左侧边缘开始拖动,系统觉得难以确定,到底是要去触发全局侧滑菜单,还是触发页面内的返回操作。在iOS 7以及后续更高版本当中,导航控制器的边缘返回手势成为了标准配置,这就让此问题变得更加普遍起来 ,开发者必须编写代码,来明确手势的响应优先级以及协作逻辑 。
核心解决逻辑
冲突解决的关键所在是手势识别器的代理方法这个点,需在UIGestureRecognizerDelegate的“gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:”此方法中妥善加以处理。当检测到,自定义的滑动手势,跟导航控制器的边缘返回手势,处在同时存在的情况时,能让该方法返回 YES。从而允许两者同时进行识别 。
但这会引出新的问题,同时开展识别,有致使在侧滑菜单处于半开情形时,稍有一点滑动,便会触发页面返回的可能。所以,要有更精细的控制 。我们能在手势代理方法中,按照侧滑菜单视图当前所处的位置(如它的frame.origin.x的值)来判断是否禁用导航控制器的返回手势,从而实现手势的互斥管理 。
侧滑位置的精确定位
再一个核心问题是,在侧滑终止的时候,对于侧边栏视图最终的定位。今日头条呈现出的情形是, 当侧边栏滑动过完之后,显现出这般两种状态,要么是彻底收回即复位,要么是彻底滑出来也就 是展示,而不会在屏幕的中间处停留。对这一最终状态的判断,要依照拖拽手势止息时的速度, 也就是velocity,还有位移,也就是translation来开展。
当于具体的实现动作所涉及的操作进程之中,处于手势所处的UIGestureRecognizerStateEnded状态之际,能够着手开展对应的处理手段。进而对出现做大手势动作该项活动环节时,体现于x轴方向上所包含有的速度之属性特征予以计算,若速度情形呈现为正值且大于预先设定好的某一个限定的阈值情形,或者是在进行拖拽这一动作时所产生的由此带动出现的位移,其值超出了侧边栏所标定的宽度的一半,那么借助UIView动画过程这一方式把侧边栏视图移至完全精准就位且顺利实现展示的精确位置,要是处于相反的各种情况之下的话,就凭借动画使其复位到显示器屏幕靠近左侧边沿外部处 。
视图层级的正确搭建
通常情况下,视图层级正确是功能得以实现的基础,侧滑菜单也就是个人中心页面的视图即menuView,被当作呈独立状态的某个子视图,通过addSubview方法添加到主窗口也就是keyWindow或者根视图控制器也就是rootViewController的视图上面,并且处于主内容视图也就是contentView的下方。
最开始的时候,想要达成那种全面覆盖的效果,是能够将menuView的frame放置于屏幕左边看不到的地方的,在对主内容视图进行拖动这个动作的时候,凭借改变它的x坐标来实现滑动的那种效果,而且,一定要确保menuView和contentView的层级关系是正确无误的,避免出现相互遮挡从而导致触摸事件没办法进行传递。
关键代码实现步骤
_panGestureRecognizer=[[UIPanGestureRecognizer alloc]initWithtarget:self action:@selector(panGesture:)]; _panGestureRecognizer.delegate=self; [self.navigationController.view addGestureRecognizer:_panGestureRecognizer];
新增一个UIPanGestureRecognizer属性,第二步之时,在进行视图加载如视图加载当中那个方法(viewDidLoad),将这个拖动手势放置到主内容视图(contentView)表层之上方,紧接着,在相关方法内达成手势处理处理此即那个方法(handlePan:)根据手势状态(state)以及位移(translation)计算并更新contentView的帧位置 。
解决冲突的关键代码处于手势代理方法中,除了要允许同时进行识别,还需增加条件判断,即当侧滑菜单展开时,也就是menuView.frame.origin.x的值大于0时,要主动将导航控制器的interactivePopGestureRecognizer.enabled属性设为NO,用以禁用返回手势,当菜单收起时,再把该属性恢复为YES。
//平移
-(void)panGesture:(UIPanGestureRecognizer*)pan
{
//在View中的位置
// CGPoint point=[pan locationInView:self.navigationController.view];
//在View中的移动量 以手指按下的为原点
CGPoint point1=[pan translationInView:self.navigationController.view];
if (pan.state==UIGestureRecognizerStateChanged&&pan==_panGestureRecognizer) {
if (point1.x>0&&self.navigationController.view.frame.origin.xself.navigationController.view.frame.size.width-100?self.navigationController.view.frame.size.width-100:self.navigationController.view.frame.origin.x+point1.x;
self.navigationController.view.frame=CGRectMake(x, self.navigationController.view.frame.origin.y, self.navigationController.view.frame.size.width, self.navigationController.view.frame.size.height);
NSLog(@"%@",NSStringFromCGRect(self.navigationController.view.frame));
}
else if(point1.x<0)
{
NSLog(@"aaa %f",self.navigatiojavascriptnController.view.frame.origin.x);
float x=self.navigationController.view.frame.o编程客栈rigin.x+point1.x<0?0:self.navigationController.view.frame.origin.x+point1.x;
self.navigationController.view.frame=CGRectMake(x, self.navigationController.view.frame.origin.y, self.navigationController.view.frame.size.width, self.navigationController.view.frame.size.height);
}
}
else if(pan.state==UIGestureRecognizerStateEnded)
{
if (self.navigationController.view.frame.origin.x>self.navigationController.view.frame.size.width/3) {
[UIView animateWithDuration:0.2 animations:^{
self.navigationController.view.frame=CGRectMake(self.navigationController.view.frame.size.width-100, 0, self.navigationController.view.frame.size.width, self.navigationController.view.frame.size.height);
} completion:^(BOOL finished) {
self.bottomScrollView.scrollEnabled=YES;
}];
}
else
{
[UIView animateWithDuration:0.2 animations:^{
self.navigationController.view.frame=CGRectMake(0, 0, self.navigationController.view.frame.size.width, self.navigationController.view.frame.size.height);
} completion:^(BOOL finished) {
self.bottomScrollView.scrollEnabled=YES;
}];
}
}
//偏移量是增加的应该设为0
[pan setTranslation:CGPointZero inView:self.navigationController.view];
}
性能与体验优化
把基础功能处理完毕以后,但同样得把目光放在性能以及视觉体验上,举例来讲,可以给侧滑进程加入弹簧动画效果(usingSpringForDamping),以此让滑动更自然些,与此同时,得留意在侧滑菜单打开的时候,给主内容视图加半透明遮罩或者缩放效果,并且给它加个点击手势用于收回菜单。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (self.bottomScrollView.contentOffset.x<=0.0&&gestureRecognizer==_panGestureRecognizer) {
if (self.navigationController.view.frame.origin.x>0) {
self.bottomScrollView.scrollEnabled=NO;
}
else
{
self.bottomScrollView.scrollEnabled=YES;
}
return YES;
}
return NO;
}
此外,需妥善处置好设备转动的时候,也就是屏幕方向发生改变之际视图的布局适配,在iOS 8以及之后的版本里,建议将布局代码撰写在viewDidLayoutSubviews方法当中,借此保障侧滑菜单在各类屏幕尺寸的情形下都能够准确实现定位。
在致力实现这类复杂交互之时,遭遇了那种极难调试的问题,究竟是手势冲突的细节这一方面呀,还是动画流畅度的调优这一状况呢?于评论区里乐意分享你的经验,倘若觉得本文对你存有帮助,也一定要点赞并且分享给更多数量的开发者朋友。
同类文章排行
- 新手不会写新闻稿?掌握这三部分写作技巧就
- 8月29日晚江苏银行发布半年报,经营业绩
- 宁波立夏习俗活动热闹开展,传承文化乐趣多
- 全国爱肝日关注肝硬化逆转,这些伤肝行为千
- 2025年6月网络谣言聚焦热点领域,造谣
- 2021一点资讯今日头条官方版:海量资讯
- 12月1日校运会拔河比赛超精彩,各班展风
- 陈冠希近照曝光形象遭吐槽,颜值变化引发网
- 青岛开发区海博家居荣获山东省服务名牌,凭
- 动态消息的含义和特点解析,快来看看怎么定
最新资讯文章
- 43岁陈冠希近照曝光似外星人,曾花心现家
- 鸡西召开生态环保督察整改会,部署任务提升
- 陈冠希近照曝光显苍老,时尚造型遭群嘲,这
- 鸡西市主要环境问题及防治对策研究(依据‘
- 陈冠希近照竟如此苍老,与昔日帅气模样判若
- 省发改委等率队来梅调研梅县机场迁建选址工
- 陈冠希近照状态差显苍老,与谢霆锋对比差距
- 梅县至珠海航班29日开通首航,打破航线格
- 陈冠希近照曝光,颜值变化大,父女出席活动
- 2023 年武汉春节返乡置业活跃,新房受
- 陈冠希近照曝光形象遭吐槽,颜值变化引发网
- 武汉楼市现况吸引新市民,肖南万先生等纷纷
- 11月13号新闻汇总:电信诈骗惩戒征求意
- 武汉楼市成交量放大但去库存难,2月房价环
- 宠物小精灵20年回顾:首发游戏纪念日,情
- 武汉楼市率先回暖复苏,小阳春下行业仍有隐
- 香港留学准备:证件必备及入学流程全攻略,
- 2月武汉住房成交大增现‘报复性’反弹,‘
- 网站平台对自媒体信息管理有这些要求,快来
- 文史丨微服私访古代皇帝真的像电视剧那么容




