Как скрыть панель вкладок с анимацией в iOS?

Итак, у меня есть кнопка, которая подключена к IBAction. Когда я нажимаю кнопку, Я хочу скрыть панель вкладок в моем приложении iOS с анимацией. Это [self setTabBarHidden:hidden animated:NO]; или это [self.tabBarController setTabBarHidden:hidden animated:YES]; не работает. Это мой код без анимации:

- (IBAction)picture1:(id)sender {
    [self.tabBarController.tabBar setHidden:YES];
}

любая помощь была бы весьма признательна :D

11 ответов


Я пытаюсь сохранить анимацию просмотра, доступную мне, используя следующую формулу:

// pass a param to describe the state change, an animated flag and a completion block matching UIView animations completion 
- (void)setTabBarVisible:(BOOL)visible animated:(BOOL)animated completion:(void (^)(BOOL))completion {

    // bail if the current state matches the desired state
    if ([self tabBarIsVisible] == visible) return (completion)? completion(YES) : nil;

    // get a frame calculation ready
    CGRect frame = self.tabBarController.tabBar.frame;
    CGFloat height = frame.size.height;
    CGFloat offsetY = (visible)? -height : height;

    // zero duration means no animation
    CGFloat duration = (animated)? 0.3 : 0.0;

    [UIView animateWithDuration:duration animations:^{
        self.tabBarController.tabBar.frame = CGRectOffset(frame, 0, offsetY);
    } completion:completion];
}

//Getter to know the current state
- (BOOL)tabBarIsVisible {
    return self.tabBarController.tabBar.frame.origin.y < CGRectGetMaxY(self.view.frame);
}

//An illustration of a call to toggle current state
- (IBAction)pressedButton:(id)sender {
    [self setTabBarVisible:![self tabBarIsVisible] animated:YES completion:^(BOOL finished) {
        NSLog(@"finished");
    }];
}

при работе с раскадровкой его легко настроить контроллер вида, чтобы скрыть вкладку на push, на контроллере вида назначения просто установите этот флажок:
enter image description here


в соответствии с Apple docs, hidesBottomBarWhenPushed свойство UIViewController, логическое значение, указывающее, скрыта ли панель инструментов в нижней части экрана, когда контроллер вида нажата на навигационный контроллер.

значение этого свойства на контроллере верхнего вида определяет, видна ли панель инструментов.

рекомендуемый подход для скрытия панели вкладок будет следующим образом

    ViewController *viewController = [[ViewController alloc] init];
    viewController.hidesBottomBarWhenPushed = YES;  // This property needs to be set before pushing viewController to the navigationController's stack. 
    [self.navigationController pushViewController:viewController animated:YES];

однако обратите внимание, что этот подход будет только применяется к соответствующему viewController и не будет распространяться на другие контроллеры представления, если вы не начнете устанавливать то же свойство hidesBottomBarWhenPushed в других viewControllers, прежде чем толкать его в стек навигационного контроллера.


версия Swift 3.0, используя расширение:

extension UITabBarController {

    private struct AssociatedKeys {
        // Declare a global var to produce a unique address as the assoc object handle
        static var orgFrameView:     UInt8 = 0
        static var movedFrameView:   UInt8 = 1
    }

    var orgFrameView:CGRect? {
        get { return objc_getAssociatedObject(self, &AssociatedKeys.orgFrameView) as? CGRect }
        set { objc_setAssociatedObject(self, &AssociatedKeys.orgFrameView, newValue, .OBJC_ASSOCIATION_COPY) }
    }

    var movedFrameView:CGRect? {
        get { return objc_getAssociatedObject(self, &AssociatedKeys.movedFrameView) as? CGRect }
        set { objc_setAssociatedObject(self, &AssociatedKeys.movedFrameView, newValue, .OBJC_ASSOCIATION_COPY) }
    }

    override open func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        if let movedFrameView = movedFrameView {
            view.frame = movedFrameView
        }
    }

    func setTabBarVisible(visible:Bool, animated:Bool) {
        //since iOS11 we have to set the background colour to the bar color it seams the navbar seams to get smaller during animation; this visually hides the top empty space...
        view.backgroundColor =  self.tabBar.barTintColor 
        // bail if the current state matches the desired state
        if (tabBarIsVisible() == visible) { return }

        //we should show it
        if visible {
            tabBar.isHidden = false
            UIView.animate(withDuration: animated ? 0.3 : 0.0) {
                //restore form or frames
                self.view.frame = self.orgFrameView!
                //errase the stored locations so that...
                self.orgFrameView = nil
                self.movedFrameView = nil
                //...the layoutIfNeeded() does not move them again!
                self.view.layoutIfNeeded()
            }
        }
            //we should hide it
        else {
            //safe org positions
            orgFrameView   = view.frame
            // get a frame calculation ready
            let offsetY = self.tabBar.frame.size.height
            movedFrameView = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height + offsetY)
            //animate
            UIView.animate(withDuration: animated ? 0.3 : 0.0, animations: {
                self.view.frame = self.movedFrameView!
                self.view.layoutIfNeeded()
            }) {
                (_) in
                self.tabBar.isHidden = true
            }
        }
    }

    func tabBarIsVisible() ->Bool {
        return orgFrameView == nil
    }
}
  • это основано на вводе от Шервина Заде после нескольких часов игры.
  • вместо того, чтобы перемещать саму панель табуляции, она перемещает рамку представления, это эффективно скользит панель табуляции красиво из нижней части экрана, но...
  • ... имеет то преимущество, что содержимое, отображаемое внутри UITabbarcontroller, также принимает полный экран!
  • обратите внимание на его также использование функциональности AssociatedObject для прикрепления данных к UIView без подклассов и, следовательно, расширение возможно (расширения не позволяют хранить свойства)

enter image description here


Swift Версия:

@IBAction func tap(sender: AnyObject) {
    setTabBarVisible(!tabBarIsVisible(), animated: true, completion: {_ in })
}


// pass a param to describe the state change, an animated flag and a completion block matching UIView animations completion
func setTabBarVisible(visible: Bool, animated: Bool, completion:(Bool)->Void) {

    // bail if the current state matches the desired state
    if (tabBarIsVisible() == visible) {
        return completion(true)
    }

    // get a frame calculation ready
    let height = tabBarController!.tabBar.frame.size.height
    let offsetY = (visible ? -height : height)

    // zero duration means no animation
    let duration = (animated ? 0.3 : 0.0)

    UIView.animateWithDuration(duration, animations: {
        let frame = self.tabBarController!.tabBar.frame
        self.tabBarController!.tabBar.frame = CGRectOffset(frame, 0, offsetY);
    }, completion:completion)
}

func tabBarIsVisible() -> Bool {
    return tabBarController!.tabBar.frame.origin.y < CGRectGetMaxY(view.frame)
}

попробуйте установить рамку таббара в анимации. См.этой учебник.

просто имейте в виду, это плохая практика, чтобы сделать это, вы должны установить Показать / Скрыть таббар, когда UIViewController push by установить свойство hidesBottomBarWhenPushed to YES.


перепишите ответ Шервина Заде в Swift 4:

/* tab bar hide/show animation */
extension AlbumViewController {
    // pass a param to describe the state change, an animated flag and a completion block matching UIView animations completion
    func setTabBarVisible(visible: Bool, animated: Bool, completion: ((Bool)->Void)? = nil ) {

        // bail if the current state matches the desired state
        if (tabBarIsVisible() == visible) {
            if let completion = completion {
                return completion(true)
            }
            else {
                return
            }
        }

        // get a frame calculation ready
        let height = tabBarController!.tabBar.frame.size.height
        let offsetY = (visible ? -height : height)

        // zero duration means no animation
        let duration = (animated ? kFullScreenAnimationTime : 0.0)

        UIView.animate(withDuration: duration, animations: {
            let frame = self.tabBarController!.tabBar.frame
            self.tabBarController!.tabBar.frame = frame.offsetBy(dx: 0, dy: offsetY)
        }, completion:completion)
    }

    func tabBarIsVisible() -> Bool {
        return tabBarController!.tabBar.frame.origin.y < view.frame.maxY
    }
}

пробовал в swift 3.0 / iOS10 / Xcode 8:

    self.tabBarController?.tabBar.isHidden = true

Я устанавливаю его, когда отображается мой контроллер: (и скрыть, когда назад, после навигации)

override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)
        self.tabBarController?.tabBar.isHidden = false

    }

    override func viewWillDisappear(_ animated: Bool) {
                super.viewWillDisappear(animated)
        self.tabBarController?.tabBar.isHidden = true

    }

BTW: лучше иметь флаг для сохранения, если он показан или нет, так как другие вентиляционные отверстия могут в конечном итоге вызвать hide/show


к сожалению, я не могу прокомментировать ответ Хиксфилда, потому что у меня недостаточно репутации, поэтому я должен оставить это как отдельный ответ.

в его ответе отсутствует вычисляемое свойство для movedFrameView, которая составляет:

var movedFrameView:CGRect? {
  get { return objc_getAssociatedObject(self, &AssociatedKeys.movedFrameView) as? CGRect }
  set { objc_setAssociatedObject(self, &AssociatedKeys.movedFrameView, newValue, .OBJC_ASSOCIATION_COPY) }
}

основываясь на ответе Хиксфилда и била Чана, я подготовил версию, которая работает на iOS 9 для iOS 11 (я не могу тестировать на других версиях прямо сейчас) и iPhone 4S для iPhone X (протестировано). Если вы хотите скрыть панель вкладок, просто позвоните:tabBarController?.set(visible:false, animated: true), Если вы хотите показать звоните: tabBarController?.set(visible:true, animated: true). Вы также можете найти этот код в моем gist:https://gist.github.com/MaciejGad/9a4d1f65dcf382373911c90c548d2713

extension UITabBarController {

func set(visible: Bool, animated: Bool, completion: ((Bool)->Void)? = nil ) {

    guard isVisible() != visible else {
        completion?(true)
        return
    }

    let offsetY = tabBar.frame.size.height
    let duration = (animated ? 0.3 : 0.0)

    let beginTransform:CGAffineTransform
    let endTransform:CGAffineTransform

    if visible {
        beginTransform = CGAffineTransform(translationX: 0, y: offsetY)
        endTransform = CGAffineTransform.identity
    } else {
        beginTransform = CGAffineTransform.identity
        endTransform = CGAffineTransform(translationX: 0, y: offsetY)
    }

    tabBar.transform = beginTransform
    if visible {
        tabBar.isHidden = false
    }

    UIView.animate(withDuration: duration, animations: {
        self.tabBar.transform = endTransform
    }, completion: { compete in
        completion?(compete)
        if !visible {
            self.tabBar.isHidden = true
        }
    })
}

func isVisible() -> Bool {
    return !tabBar.isHidden
}
}

Это wrks для меня: [self.tabBar setHidden:YES];
где self - это контроллер вида, tabBar-это идентификатор для tabBar.