Comment cacher la barre d'onglets avec l'animation dans iOS?
donc j'ai un bouton qui est connecté à une IBAction. Lorsque j'appuie sur le bouton je veux masquer la barre d'onglets dans mon application iOS avec une animation. Ce [self setTabBarHidden:hidden animated:NO];
ou ce [self.tabBarController setTabBarHidden:hidden animated:YES];
ne fonctionne pas. C'est mon code sans l'animation:
- (IBAction)picture1:(id)sender {
[self.tabBarController.tabBar setHidden:YES];
}
toute aide serait grandement appréciée: d
11 réponses
j'essaie de garder les animations de vue disponibles pour moi en utilisant la formule suivante:
// 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");
}];
}
quand on travaille avec storyboard il est facile de configurer le contrôleur de vue pour cacher la barre de Tab sur push, sur le contrôleur de vue de destination il suffit de sélectionner cette case à cocher:
comme pour Apple docs, hidesBottomBarWhenPushed propriété de UIViewController, une valeur booléenne, indiquant si la barre d'outils au bas de l'écran est cachée lorsque le contrôleur de vue est poussé sur un contrôleur de navigation.
la valeur de cette propriété sur le contrôleur de vue supérieur détermine si la barre d'outils est visible.
L'approche recommandée pour masquer la barre d'onglets serait comme suit:
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];
Cependant, notez que cette approche ne sera appliquée qu'aux viewControllers respectifs et ne sera pas propagée à d'autres contrôleurs de vue à moins que vous ne commenciez à définir la même propriété hidesBottomBarWhenPushed dans d'autres viewControllers avant de la pousser vers la pile du contrôleur de navigation.
version Swift 3.0, en utilisant une extension:
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
}
}
- C'est basé sur l'entrée de Sherwin Zadeh après quelques heures de jeu environ.
- au lieu de déplacer le tabbar lui-même il déplace le cadre de la vue, ce qui glisse effectivement le tabbar gentiment hors du bas de l'écran mais...
- ... a l'avantage que le contenu affiché à L'intérieur du UITabbarcontroller prend alors aussi le plein écran!
- note son également à l'aide de la AssociatedObject de la fonctionnalité de données attachées à la UIView sans sous-classement et donc une extension est possible (extensions de ne pas autoriser stockées les propriétés)
Version 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)
}
réécrire la réponse de Sherwin Zadeh dans 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
}
}
essayé dans swift 3.0 / iOS10/ Xcode 8:
self.tabBarController?.tabBar.isHidden = true
je le règle quand mon contrôleur est affiché: (et je le cache quand je reviens, après la navigation)
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: il est préférable d'avoir un drapeau à sauvegarder s'il est affiché ou non, car d'autres évents peuvent éventuellement déclencher hide /show
malheureusement, Je ne peux pas commenter la réponse de HixField parce que je n'ai pas assez de réputation, donc je dois laisser ceci comme une réponse séparée.
sa réponse est l'absence de la propriété calculée pour movedFrameView
, qui est:
var movedFrameView:CGRect? {
get { return objc_getAssociatedObject(self, &AssociatedKeys.movedFrameView) as? CGRect }
set { objc_setAssociatedObject(self, &AssociatedKeys.movedFrameView, newValue, .OBJC_ASSOCIATION_COPY) }
}
basé sur la réponse de HixField et Bil Chan j'ai préparé une version qui fonctionne sur iOS 9 à iOS 11 (Je ne peux pas tester sur d'autres versions en ce moment), et iPhone 4S à iPhone X (testé). Quand vous voulez cacher la barre d'onglets il suffit d'appeler: tabBarController?.set(visible:false, animated: true)
, de même si vous voulez montrer appel: tabBarController?.set(visible:true, animated: true)
. Vous pouvez aussi trouver ce code dans mon 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
}
}
C'est pour moi:
[self.tabBar setHidden:YES];
où self est le contrôleur de vue, tabBar est l'id pour la tabBar.