iOS / Swift - 向下/向上滚动时隐藏/显示UITabBarController

时间:2015-08-10 20:18:22

标签: ios swift uiscrollview uitabbarcontroller show-hide

我对iOS开发很新。现在我正在尝试隐藏我的标签栏,当我向下滚动时,向上滚动标签栏应该出现。我想像导航栏一样以动画制作动画。对于导航栏,我只需单击“属性”检查器中的选项。我看到了工具栏的一些示例,但我不能将其作为标签栏。

self.tabBarController?.tabBar.hidden = true只是隐藏我的标签栏,但它不像导航控制器那样动画。

6 个答案:

答案 0 :(得分:33)

这是我实际在生产应用中使用的代码。

它位于 Swift 中,它还会更新UITabBar.hidden var。

func scrollViewWillBeginDragging(scrollView: UIScrollView) {
    if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0{
        changeTabBar(hidden: true, animated: true)
    }
    else{
        changeTabBar(hidden: false, animated: true)
    }
}

您还可以使用其他回调方法:

func scrollViewDidScroll(scrollView: UIScrollView) {
    ...
}

但如果您选择这样,那么您必须处理多个实际隐藏tabBar的辅助方法的调用。

然后你需要添加这个方法来激活tabBar的隐藏/显示。

func changeTabBar(hidden:Bool, animated: Bool){
    var tabBar = self.tabBarController?.tabBar
    if tabBar!.hidden == hidden{ return }
    let frame = tabBar?.frame
    let offset = (hidden ? (frame?.size.height)! : -(frame?.size.height)!)
    let duration:NSTimeInterval = (animated ? 0.5 : 0.0)
    tabBar?.hidden = false
    if frame != nil
    {
        UIView.animateWithDuration(duration,
            animations: {tabBar!.frame = CGRectOffset(frame!, 0, offset)},
            completion: {
                println($0)
                if $0 {tabBar?.hidden = hidden}
        })
    }
}

更新Swift 4

func changeTabBar(hidden:Bool, animated: Bool){
    guard let tabBar = self.tabBarController?.tabBar else { return; }
    if tabBar.isHidden == hidden{ return }
    let frame = tabBar.frame
    let offset = hidden ? frame.size.height : -frame.size.height
    let duration:TimeInterval = (animated ? 0.5 : 0.0)
    tabBar.isHidden = false

    UIView.animate(withDuration: duration, animations: {
        tabBar.frame = frame.offsetBy(dx: 0, dy: offset)
    }, completion: { (true) in
        tabBar.isHidden = hidden
    })
}

答案 1 :(得分:5)

在Ariel的回答基础上,我更新了 Swift3 的代码。这对我的收藏视图很有用。

override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0 {
            changeTabBar(hidden: true, animated: true)
        }else{
            changeTabBar(hidden: false, animated: true)
        }

    }

func changeTabBar(hidden:Bool, animated: Bool){
        let tabBar = self.tabBarController?.tabBar
        if tabBar!.isHidden == hidden{ return }
        let frame = tabBar?.frame
        let offset = (hidden ? (frame?.size.height)! : -(frame?.size.height)!)
        let duration:TimeInterval = (animated ? 0.5 : 0.0)
        tabBar?.isHidden = false
        if frame != nil
        {
            UIView.animate(withDuration: duration,
                                       animations: {tabBar!.frame = frame!.offsetBy(dx: 0, dy: offset)},
                                       completion: {
                                        print($0)
                                        if $0 {tabBar?.isHidden = hidden}
            })
        }
    }

答案 2 :(得分:4)

这个答案是对Ariel答案的略微修改,在用户滚动时添加动画。

extension ViewController:UIScrollViewDelegate{
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0{
            //scrolling down
            changeTabBar(hidden: true, animated: true)
        }
        else{
            //scrolling up
            changeTabBar(hidden: false, animated: true)
        }
    }

    func changeTabBar(hidden:Bool, animated: Bool){
        let tabBar = self.tabBarController?.tabBar
        let offset = (hidden ? UIScreen.main.bounds.size.height : UIScreen.main.bounds.size.height - (tabBar?.frame.size.height)! )
        if offset == tabBar?.frame.origin.y {return}
        print("changing origin y position")
        let duration:TimeInterval = (animated ? 0.5 : 0.0)
        UIView.animate(withDuration: duration,
                       animations: {tabBar!.frame.origin.y = offset},
                       completion:nil)
    }
}

答案 3 :(得分:0)

您可以通过将类设置为scrollView的委托并在#define LIMIT(__VALUE__, __MIN__, __MAX__) MAX(__MIN__, MIN(__MAX__, __VALUE__)) - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat scrollOffset = scrollView.contentOffset.y; CGFloat scrollDiff = scrollOffset - self.previousScrollViewYOffset; CGFloat scrollHeight = scrollView.frame.size.height; CGFloat scrollContentSizeHeight = scrollView.contentSize.height + scrollView.contentInset.bottom; CGFloat scrollOffsetGlobal = scrollOffset + scrollView.contentInset.top; [self updateUITabBarY:[self UITabBarView].frame.origin.y + scrollDiff]; self.previousScrollViewYOffset = scrollOffset; } - (UITabBar*) UITabBarView { for(UIView *view in self.tabBarController.view.subviews) { if([view isKindOfClass:[UITabBar class]]) { return (UITabBar*) view; } } return nil; } - (void) updateUITabBarY:(CGFloat) y { UITabBar* tabBar = [self UITabBarView]; if(tabBar) { CGRect frame = tabBar.frame; frame.origin.y = LIMIT(y, [self UITabBarMiny], [self UITabBarMaxY]); tabBar.frame = frame; } } - (CGFloat) UITabBarMiny { return [UIScreen mainScreen].bounds.size.height - [self UITabBarView].frame.size.height - [[UIApplication sharedApplication] statusBarFrame].size.height + 20.0f; } - (CGFloat) UITabBarMaxY { return [UIScreen mainScreen].bounds.size.height; } 方法中实现滚动来精确地控制UITabBar。

以下是我如何使用我的应用程序的示例。您可以根据需要轻松修改它。一些辅助函数可以包含UITabBar。

    /*Table was deleted*/
public void deleteProducts(){
    SQLiteDatabase db = getWritableDatabase();
    db.execSQL("DROP TABLE "+TABLE_PRODUCTS);
}

答案 4 :(得分:0)

根据@ArielHernándezAmador隐藏Tabbar后的黑屏答案,只需在ViewDidLoad()中使用此行代码即可。工作出色...我已在此处发布了此内容,因为我无法在那发表评论。

viewDidLoad()
{
if #available(iOS 11.0, *) {
            self.myScroll.contentInsetAdjustmentBehavior = .never
        }
}

这里,myScroll是我在VC中使用的Scrollview。只需将其替换为您的VC。

答案 5 :(得分:0)

Ariels 的回答有效,但有些值似乎不合适。当您比较 scrollView scrollView.panGestureRecognizer.translation(in: scrollView).y 的 y 值时,“0”有副作用,即当您停止滚动时 tabBar 会显示或隐藏。它以“0”值再次调用该方法。我用 didEndDragging、didScroll 和 willBeginDragging 尝试了类似的效果。这感觉非常违反直觉或错误。 我在比较 y 值时使用了 +/- 0.1 并获得了所需的效果,当您真正向上或向下滚动时,它只会显示和隐藏。

另一件未提及的事情是,当应用移至后台时,您使用 tabBar.frame = frame.offsetBy(dx: 0, dy: offset) 设置的偏移量将被重置。您向下滚动,tabBar 消失,您更改应用程序,再次打开它,tabBar 仍然隐藏,但框架又回到了旧位置。所以当再次调用该函数时,tabBar 向上移动的幅度更大,并且与 tabBar.frame 的大小有差距。

为了摆脱这种情况,我比较了当前帧位置并对 alpha 值进行了动画处理。我无法让通常的回归动画工作,也许有人会尝试,不会那么难。不过这样也没关系,因为这种情况并不经常发生。

override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

    let yValue = scrollView.panGestureRecognizer.translation(in: scrollView).y
    if yValue < -0.1 {
        //hide tabBar
        changeTabBar(hidden: true, animated: true)
    } else if yValue > 0.1 {
        //show tabBar
        changeTabBar(hidden: false, animated: true)
    }
}

func changeTabBar(hidden:Bool, animated: Bool) {
    guard let tabBar = self.tabBarController?.tabBar else {
        return
    }
    if tabBar.isHidden == hidden{
        return
    }
    
    let frame = tabBar.frame
    let frameMinY = frame.minY  //lower end of tabBar
    let offset = hidden ? frame.size.height : -frame.size.height
    let viewHeight = self.view.frame.height
    
    //hidden but moved back up after moving app to background
    if frameMinY < viewHeight && tabBar.isHidden {
        tabBar.alpha = 0
        tabBar.isHidden = false

        UIView.animate(withDuration: 0.5) {
            tabBar.alpha = 1
        }
        
        return
    }

    let duration:TimeInterval = (animated ? 0.5 : 0.0)
    tabBar.isHidden = false

    UIView.animate(withDuration: duration, animations: {
        tabBar.frame = frame.offsetBy(dx: 0, dy: offset)
    }, completion: { (true) in
        tabBar.isHidden = hidden
    })
}