怎样使用 UIPanGestureRecognizer 限制被绑定 view 的滑动区域(手机党注意有动图) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
Shared
V2EX    iDev

怎样使用 UIPanGestureRecognizer 限制被绑定 view 的滑动区域(手机党注意有动图)

  •  
  •   Shared
    vayn 2015-10-26 21:09:14 +08:00 6062 次点击
    这是一个创建于 3639 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这两天学习 iOS 开发,尝试制作一个左滑菜单,目前已经实现了大部分功能。不过现在碰到一个棘手问题

    问题

    通过 UIPanGestureRecognizer 可以给菜单增加向右滑动收缩的手势,可是如果直接绑定手势,菜单在完全弹出后还能再向右侧滑……于是就有了下面的奇怪效果:

    slide menu

    失败方案

    我想限制菜单如果已完全弹出就只能左滑,于是在 UIGestureRecognizerStateChanged 状态下加入检查代码:

    CGPoint velocity = [(UIPanGestureRecognizer *)sender velocityInView:self.view];
    if (self.slideMenuView.frame.origin.x > 0 && velocity > 0) return;

    我的想法是 slideMenuView 如果完全弹出,那么它的 origin.x 应该是 0,如果大于 0 且方向往右,就不更新位置。

    似乎有用,不过如果先向左滑,再向右以很快的速度滑动,检查就会失效:

    slide menu 2

    求解答

    我要实现的滑动菜单和网上流行的效果不样,找了半天没找到相关文档,现在只能向各位高手求教了。希望各位能帮忙分析一下问题出在哪里,谢谢啊~

    第 1 条附言    2015-10-26 23:00:27 +08:00
    我把代码上传到 Github 了,各位可以自己跑一下试试

    https://github.com/vayn/ice
    16 条回复    2015-11-16 20:34:03 +08:00
    anerevol
        1
    anerevol  
       2015-10-26 21:35:25 +08:00
    可不可以在设置 frame 时候判断,例如:
    func setSlideMenuViewFrame(frame: CGRect) {
    if frame.origin.x > MAX_X {
    frame.origin.x = MAX_X
    }
    self.slideMenuView.frame = frame
    }
    Shared
        2
    Shared  
    OP
       2015-10-26 21:52:27 +08:00
    @anerevol 可是在哪里设置呢,如果是在检查状态的地方的设置,结果是一样的
    anerevol
        3
    anerevol  
       2015-10-26 22:11:33 +08:00
    不需要检查状态,直接设置。
    你的目的是菜单右滑不超过最大值,那你保证任何时候设置菜单 frame 的时候不超过最大值即可。
    如果觉得我说的方法无效,请忽略。
    Shared
        4
    Shared  
    OP
       2015-10-26 22:25:28 +08:00
    @anerevol 我试了,没有效果……
    Shared
        5
    Shared  
    OP
       2015-10-26 23:00:59 +08:00
    @anerevol 我把代码上传到 Github 了,各位可以自己跑一下试试

    https://github.com/vayn/ice
    PhilCai
        6
    PhilCai  
       2015-10-27 11:07:36 +08:00   1
    - (void)movelMenu:(UIGestureRecognizer *)sender {
    [[[(UITapGestureRecognizer *)sender view] layer] removeAllAnimations];

    CGPoint translatedPoint =
    [(UIPanGestureRecognizer *)sender translationInView:self.view];
    CGPoint velocity =
    [(UIPanGestureRecognizer *)sender velocityInView:self.view];

    if (sender.state == UIGestureRecognizerStateEnded) {
    if (velocity.x > 0) {
    NSLog(@"gesture went right");
    } else {
    NSLog(@"gesture went left");
    }

    if (!self.showMenu) {
    [self moveMenuToOriginalPosition];
    } else {
    if (self.showingSlideMenu) {
    [self moveMenuRight];
    }
    }
    }

    if (sender.state == UIGestureRecognizerStateChanged) {

    self.showMenu = sender.view.center.x > 0;

    [sender view].center = CGPointMake(
    [sender view].center.x + translatedPoint.x, [sender view].center.y);
    [(UIPanGestureRecognizer *)sender setTranslation:CGPointZero
    inView:self.view];

    self.preVelocity = velocity;
    if (sender.view.frame.origin.x >= 0) {
    sender.view.frame = CGRectMake(0, sender.view.frame.origin.y,
    sender.view.frame.size.width,
    sender.view.frame.size.height);
    }
    }
    }
    wezzard
        7
    wezzard  
       2015-10-27 11:16:57 +08:00
    UIPanGestureRecognizer is super raw. Use UIScrollView with pagingEnabled set to YES.
    Shared
        8
    Shared  
    OP
       2015-10-27 15:30:09 +08:00
    @wezzard Do you mean that I need set SlideMenuView as a subview of UIScrollView and set pagingEnabled to YES?
    Shared
        9
    Shared  
    OP
       2015-10-27 15:30:29 +08:00
    @PhilCai 谢谢,我晚上回去试试。
    Shared
        10
    Shared  
    OP
       2015-10-27 18:43:23 +08:00
    @PhilCai 谢谢,成功了!能讲讲为什么把对 slideMenuView.origin.x 的检查发在状态检查的最后就出现越界的情况呢?
    Shared
        11
    Shared  
    OP
       2015-10-27 21:30:38 +08:00
    @PhilCai 我想了一下确实只能放在最后,否则 slide menu view 就不能拖动了。
    如果加上 velocity.x > 0 倒是可以放前面,但快速右滑再左滑的时候,我猜想 velocity.x 在一瞬间为 0 ,然后 view.orgin.x 又大于 0 ,就出现了一个 gap 。综上所述,只能把检查放在更新的最后,作为纠正手段。

    不知道这么想对不对?
    PhilCai
        12
    PhilCai  
       2015-10-28 00:51:07 +08:00   1
    @Shared 我没仔细看, 网上有很多侧滑啊,SWRevealViewController 什么的, 你看看他们的
    Shared
        13
    Shared  
    OP
       2015-10-28 01:03:40 +08:00
    @PhilCai SWRevealViewController 这些都是侧滑主界面,和侧滑菜单还不一样。无论如何谢谢你的解答
    Galvin
        14
    Galvin  
       2015-11-16 19:39:19 +08:00
    设置 frame 的时候
    假设菜单为 menuView
    distance 为滑动的距离
    那么 frame.origin.x = MAX(-menuView.size.width,MIN(0,distance))
    不需要用到 if else 就能限定 menu 的位置了
    Galvin
        15
    Galvin  
       2015-11-16 19:40:27 +08:00   1
    @Galvin 更正一下
    distance 其实就是滑动的那个 offset 可以为正或者负
    Shared
        16
    Shared  
    OP
       2015-11-16 20:34:03 +08:00
    @Galvin 我明白你的意思了。其实就是限定 view.origin.x 在一个固定区间里,用的你方法比用 if 语句思路上清晰多了。哈哈,如果 Objective-C 支持 Python 的 a<b<c 就更棒了。

    多谢 。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1368 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 16:43 PVG 00:43 LAX 09:43 JFK 12:43
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86