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日晚江苏银行发布半年报,经营业绩
- 新手不会写新闻稿?掌握这三部分写作技巧就
- 宁波立夏习俗活动热闹开展,传承文化乐趣多
- 全国爱肝日关注肝硬化逆转,这些伤肝行为千
- 2021一点资讯今日头条官方版:海量资讯
- 12月1日校运会拔河比赛超精彩,各班展风
- 2025年6月网络谣言聚焦热点领域,造谣
- 陈冠希近照曝光形象遭吐槽,颜值变化引发网
- 青岛开发区海博家居荣获山东省服务名牌,凭
- 动态消息的含义和特点解析,快来看看怎么定
最新资讯文章
- 湖北房县秋酿黄酒忙,市场监管局助力产业高
- 全国新闻学专业大学排名,这些学校实力强!
- 湖北房县黄酒年产值破40亿,背后监管密码
- 广东大学新闻学专业排名,暨大在全国排第几
- 湖北房县工商联携手异地商会,推动黄酒成全
- 热门新闻app推荐:新浪、上观及海大新闻
- 韩国女子迷信整容致毁容,涉事医生面临刑事
- 部队干部集训新闻报道稿范文 公司军训通讯
- 四川女孩盼借媒体帮实现韩国免费整形梦,活
- 亳州珍宝岛药业:推动中药产业升级,引领中
- 亳州珍宝岛药业为子公司亳州交易中心向农行
- 韩国整容现消费陷阱,同样项目对中国顾客收
- 奥斯维辛没有什么新闻ppt:多种类型,助
- 2024中国LED照明灯饰行业100强情
- 陕西石泉县近期热点新闻汇总:赛事、活动、
- 就业故事四季不断,2023 年人社部门奋
- 漳州电视台推进媒体融合 打造新型主流媒体
- 十五五开局之年,如何促进高质量充分就业?
- 春节临近福建诏安县多单位联合开展森林防火
- 连云港新闻综合频道2026最新节目表




