【问题标题】:Show/hide UIToolbar, "match finger movement", precisely as in for example iOS7 Safari显示/隐藏 UIToolbar,“匹配手指移动”,就像在 iOS7 Safari 中一样
【发布时间】:2014-02-21 08:35:06
【问题描述】:

注意:在这里查看 Thuy 的 UINavBar 子类:

https://stackoverflow.com/a/20720359/294884

如果您正在解决这个问题,GTScrollNavigationBar 已经接近于解决导航栏问题的现成解决方案!

例如:在 2014 年的 iPhone 上,打开 Safari,加载任何网页。

查看底部的 iOS 工具栏。

现在上下移动你的手指只有几个像素

基本上是底部的工具栏,用手指移动。此外,工具栏稍后会在您滚动页面时出现/消失,遵循特定的逻辑。

但是交互规则非常复杂,包括隐藏时的手指开/关、距离匹配、页面下方的手势、非常短页面的特殊情况等等.

我想完全复制 Apple 的行为。

(我们应该匹配 Apple UX 似乎是明智的。)

有没有办法做到这一点? Apple 是否为此提供了一个我不知道的一步命令?还是您必须费力地复制这个概念?

谢谢。

顺便说一句,以下逻辑是可靠的,并且将大致复制苹果的做法:

-(void)feedIsScrolled:(CGFloat)scrollNewOverallYPosition
{
// call this routine when scrollViewDidScroll:

self.feedIsScrolledDelta =
 scrollNewOverallYPosition - self.feedIsScrolledPrevious;
self.feedIsScrolledPrevious =
 scrollNewOverallYPosition;

// nb, you do those only in this routine, NOT the following routine.

if ( scrollNewOverallYPosition < 15.0 )
    {
    .. animate in the bar
    return;
    }

if ( self.feedIsScrolledDelta > 0.0 )
    .. animate away the bar
}

-(void)feedIsThrown:(CGFloat)scrollNewOverallYPosition
{
// call this routine when scrollViewDidEndDragging:
// BUT ONLY when willDecelerate: is true

if ( self.feedIsScrolledDelta <= 0.0 )
    .. animate in the bar
else
    .. animate away the bar
}

顺便说一句,你当然可以使用

(void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated

上下滑动 UIToolbar。但是这对“手指匹配”没有任何帮助。

注意:例如,这里是在 SO 上看到的一个极好的解决方案:

https://stackoverflow.com/a/21049991/294884

您可以这样编程,实现 Apple 示例中的每条规则,以适应您对每一点的品味。 (当你接近底部时该怎么办,手指向上,哪个方向等等)我的意思是我只是假设有人已经完成了所有完全匹配Apple UX的工作--呵呵!

【问题讨论】:

  • 这不是 uiwebview 中的无误行为吗?
  • 您好 Raster -- 嗯,我不这么认为,不。它与 UIWebView 没有任何联系。您可以在任何滚动视图上触发
  • 顺便说一句,我没有投反对票。我怀疑是否有任何一行魔术命令可以复制这一点——它可能深埋在 Apple 的 iOS 框架代码中。这意味着您将不得不手动实施。我仍然等待纠正。
  • 感谢您链接到其他帖子。您将我的解决方案称为“临时”尝试,但它还能是什么?我的意思是,我们所能做的就是尝试匹配我们看到的行为。
  • 还要注意,UIToolbar 或者在我的情况下是UINavigationBar 并没有什么特别之处。我已经为工作中的应用程序实现了类似的行为,该应用程序在用户滚动时隐藏了自定义视图。这个概念实际上非常简单。只需根据自己的口味调整即可。

标签: ios7 uiscrollview uigesturerecognizer uitoolbar


【解决方案1】:

没有开源可以做到这一点,但我认为实现起来并不难。像 Safari 那样拥有精确的 1:1 行为可能会有些困难,但仍然可以做到。

MobileSafar 可以附加到调试器中,并使用断点和 Objective C 运行时进行调试和逆向工程。

例如,您没有使用工具栏和导航栏的两个假设是不正确的。

这是滚动前的视图层次结构:

http://pastebin.com/aRXr7b5Z

滚动后:

http://pastebin.com/CasBNuxq

如您所见,这些条已从其正常位置移开。

打破-[BrowserToolbar setFrame:],这里是堆栈跟踪:

* thread #1: tid = 0x2332c, 0x000000010003fa70 MobileSafari`___lldb_unnamed_function1519$$MobileSafari, queue = 'com.apple.main-thread', stop reason = breakpoint 8.1
  * frame #0: 0x000000010003fa70 MobileSafari`___lldb_unnamed_function1519$$MobileSafari
    frame #1: 0x0000000100023e51 MobileSafari`___lldb_unnamed_function825$$MobileSafari + 1338
    frame #2: 0x00000001000268da MobileSafari`___lldb_unnamed_function871$$MobileSafari + 55
    frame #3: 0x000000010009856a MobileSafari`___lldb_unnamed_function3864$$MobileSafari + 388
    frame #4: 0x0000000100098996 MobileSafari`___lldb_unnamed_function3871$$MobileSafari + 154
    frame #5: 0x000000010002ba89 MobileSafari`___lldb_unnamed_function990$$MobileSafari + 209
    frame #6: 0x0000000102396a8c UIKit`-[UIScrollView(UIScrollViewInternal) _notifyDidScroll] + 55
    frame #7: 0x000000010238692b UIKit`-[UIScrollView setContentOffset:] + 628
    frame #8: 0x000000010238ab00 UIKit`-[UIScrollView _updatePanGesture] + 1989
    frame #9: 0x0000000102644002 UIKit`_UIGestureRecognizerSendActions + 188
    frame #10: 0x0000000102642f68 UIKit`-[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 357
    frame #11: 0x0000000102647319 UIKit`___UIGestureRecognizerUpdate_block_invoke + 53
    frame #12: 0x00000001026472a1 UIKit`_UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 257
    frame #13: 0x000000010263f377 UIKit`_UIGestureRecognizerUpdate + 93
    frame #14: 0x0000000102353e55 UIKit`-[UIWindow _sendGesturesForEvent:] + 928
    frame #15: 0x0000000102354b14 UIKit`-[UIWindow sendEvent:] + 909
    frame #16: 0x000000010232c6da UIKit`-[UIApplication sendEvent:] + 211
    frame #17: 0x0000000102319f2d UIKit`_UIApplicationHandleEventQueue + 9579
    frame #18: 0x0000000100573f21 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #19: 0x00000001005737f2 CoreFoundation`__CFRunLoopDoSources0 + 242
    frame #20: 0x000000010058f66f CoreFoundation`__CFRunLoopRun + 767
    frame #21: 0x000000010058ef83 CoreFoundation`CFRunLoopRunSpecific + 467
    frame #22: 0x00000001011a0f04 GraphicsServices`GSEventRunModal + 161
    frame #23: 0x000000010231c273 UIKit`UIApplicationMain + 1010
    frame #24: 0x00000001000518d2 MobileSafari`___lldb_unnamed_function1998$$MobileSafari + 1558

所以这一切都发生在滚动通知之后。

我在MobileSafari'___lldb_unnamed_function990$$MobileSafari 上设置了一个断点,并获取self 变量,打印po $arg1。这就是所有魔法发生的地方:

http://pastebin.com/kjAXKKTW

如果您真的对 1:1 复制感兴趣,可以在这些方法上设置断点并进行调查。祝你好运!

【讨论】:

  • 不得不使用 pastebin 因为那些堆栈跟踪和_methodDescription 太长了。
  • 亲爱的 leo natan,既然你是天才,你可能会对这个感兴趣...stackoverflow.com/questions/23008843(令人惊讶的是,没有人解决这个问题,现在肯定是一个绝对普遍的需求,那个 UX概念!)在这里再次欢呼和感谢!
【解决方案2】:

我刚刚向 GTScrollNavigationBar 提出了一个请求,该请求有助于获得正确的“匹配手指移动”。诀窍就是根据滚动条的框架调整 ContentInsets。

它可能还不完美,但它可以满足您的需求: https://github.com/luugiathuy/GTScrollNavigationBar/pull/21

【讨论】:

    【解决方案3】:

    我使用下一个代码来隐藏 tabBar,就像在 safari 应用程序中一样。也许您或其他人可以将它与 toolBar 一起使用。

    static CGFloat navBarOriginY = 20.0;
    

    为导航栏原点 Y 位置的基值创建常量

    - (void)viewDidLoad {
    [super viewDidLoad];
     self.navigationController.hidesBarsOnSwipe = true;
    [self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipe:)];
    }
    

    添加您的自定义选择器以处理将在 navBar 隐藏之前和隐藏期间触发的系统滑动手势

    - (void)swipe:(UIPanGestureRecognizer *)recognizer {
    if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateFailed) {
    
    //If gesture state ended/canceled or failed you need entirely change frame of tabBar
    
        CGRect finalFrame = self.tabBarController.tabBar.frame;
        if (self.navigationController.navigationBar.frame.origin.y < 0) {
             //Tab bar will be hidden
            finalFrame.origin.y = self.maxTabBarY;
        } else {
             //Tab bar will be visible
            finalFrame.origin.y = self.minTabBarY;
        }
    
        [self setFrameForTabBar:finalFrame animationDuration:0.3];
    
    } else if (recognizer.state == UIGestureRecognizerStateChanged) {
    
    //If state == changed than you need to pan your tabBar with navBar like in safari app.
    
        CGRect frame = self.tabBarController.tabBar.frame;
        CGFloat delta = navBarOriginY - self.navigationController.navigationBar.layer.presentationLayer.frame.origin.y;
        frame.origin.y = self.minTabBarY + delta;
        [self setFrameForTabBar:frame animationDuration:0.0];
    } } }
    
    - (void)setFrameForTabBar:(CGRect)frame animationDuration:(CGFloat)duration {
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
            self.tabBarController.tabBar.frame = frame;
        } completion:^(BOOL finished) {}];
    });
    

    【讨论】:

      猜你喜欢
      • 2013-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-25
      • 2015-08-31
      • 1970-01-01
      • 2012-10-06
      • 2013-10-14
      相关资源
      最近更新 更多