欢迎您进入VSport体育有限公司

VSport - 胜利因您更精彩

造洁净厨房 做健康美食

油烟净化一体机批发定制首选服务商

全国免费咨询热线400-123-4567

当前位置: 主页 » 新闻动态

iOS仿网易新闻滑动菜单开发教程:解决手势冲突,实现丝滑导航

文章出处:本站 人气:发表时间:2025-12-12 02:21

众多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方法当中,借此保障侧滑菜单在各类屏幕尺寸的情形下都能够准确实现定位。

在致力实现这类复杂交互之时,遭遇了那种极难调试的问题,究竟是手势冲突的细节这一方面呀,还是动画流畅度的调优这一状况呢?于评论区里乐意分享你的经验,倘若觉得本文对你存有帮助,也一定要点赞并且分享给更多数量的开发者朋友。

同类文章排行

最新资讯文章

返回顶部