【发布时间】:2011-07-13 10:31:27
【问题描述】:
UITabBarController 有问题。在我的应用程序中,我想隐藏它但不使用hidesBottomBarWhenPushed,因为我不想在推送它时隐藏它。例如,我想在我的应用程序中按下隐藏按钮时隐藏它。
我在谷歌上阅读了很多文章,但我不知道如何做到这一点。
【问题讨论】:
标签: iphone ios uitabbarcontroller
UITabBarController 有问题。在我的应用程序中,我想隐藏它但不使用hidesBottomBarWhenPushed,因为我不想在推送它时隐藏它。例如,我想在我的应用程序中按下隐藏按钮时隐藏它。
我在谷歌上阅读了很多文章,但我不知道如何做到这一点。
【问题讨论】:
标签: iphone ios uitabbarcontroller
我正在从我的工作代码中粘贴它...您可以调用这些方法来隐藏和显示 tabbarcontroller....只需将 tabbarcontroller 实例传递给这些函数..
// Method call
[self hideTabBar:self.tabBarController];
// Method implementations
- (void)hideTabBar:(UITabBarController *) tabbarcontroller
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
for(UIView *view in tabbarcontroller.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view setFrame:CGRectMake(view.frame.origin.x, 480, view.frame.size.width, view.frame.size.height)];
}
else
{
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 480)];
}
}
[UIView commitAnimations];
}
- (void)showTabBar:(UITabBarController *) tabbarcontroller
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
for(UIView *view in tabbarcontroller.view.subviews)
{
NSLog(@"%@", view);
if([view isKindOfClass:[UITabBar class]])
{
[view setFrame:CGRectMake(view.frame.origin.x, 431, view.frame.size.width, view.frame.size.height)];
}
else
{
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, 431)];
}
}
[UIView commitAnimations];
}
【讨论】:
修改了 Setomidor 的答案,使其适用于横向、纵向和 iPad(320 和 480 值仅适用于 iPhone)。
- (void) hideTabBar:(UITabBarController *) tabbarcontroller
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
float fHeight = screenRect.size.height;
if( UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) )
{
fHeight = screenRect.size.width;
}
for(UIView *view in tabbarcontroller.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view setFrame:CGRectMake(view.frame.origin.x, fHeight, view.frame.size.width, view.frame.size.height)];
}
else
{
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
view.backgroundColor = [UIColor blackColor];
}
}
[UIView commitAnimations];
}
- (void) showTabBar:(UITabBarController *) tabbarcontroller
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
float fHeight = screenRect.size.height - tabbarcontroller.tabBar.frame.size.height;
if( UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) )
{
fHeight = screenRect.size.width - tabbarcontroller.tabBar.frame.size.height;
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
for(UIView *view in tabbarcontroller.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view setFrame:CGRectMake(view.frame.origin.x, fHeight, view.frame.size.width, view.frame.size.height)];
}
else
{
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
}
}
[UIView commitAnimations];
}
还修改了代码以处理 iOS 6 中引入的 UIDevice 方向变化的变化,并确保即使设备仰卧也能正常工作。
【讨论】:
- 49.0 替换为 tabbarcontroller.tabBar.frame.size.height 以获得更简洁的代码,在未来的 iOS 版本中破坏的可能性更小。
在按钮的操作方法中:
[self.tabBarController.tabBar setHidden:YES];
【讨论】:
Saurahb 和 karlbecker_com 的解决方案很棒,尽管当视图包含 tableview 而标签栏动画备份时,它们会导致明显的弹出效果。我做了一些修改并将其组合成一个函数(作为 UITabBarController 上的一个类别)。它并不完全完美(延迟校正动画),但使用表格时效果很好。
如果您喜欢动画块和类别,请尝试一下。方向和设备友好。
UITabBarController+ShowHideBar.m:
#import "UITabBarController+ShowHideBar.h"
@implementation UITabBarController (ShowHideBar)
- (void) setHidden:(BOOL)hidden{
CGRect screenRect = [[UIScreen mainScreen] bounds];
float fHeight = screenRect.size.height;
if( UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) ){
fHeight = screenRect.size.width;
}
if(!hidden) fHeight -= self.tabBar.frame.size.height;
[UIView animateWithDuration:0.25 animations:^{
for(UIView *view in self.view.subviews){
if([view isKindOfClass:[UITabBar class]]){
[view setFrame:CGRectMake(view.frame.origin.x, fHeight, view.frame.size.width, view.frame.size.height)];
}else{
if(hidden) [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
}
}
}completion:^(BOOL finished){
if(!hidden){
[UIView animateWithDuration:0.25 animations:^{
for(UIView *view in self.view.subviews)
{
if(![view isKindOfClass:[UITabBar class]])
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, fHeight)];
}
}];
}
}];
}
@end
UITabBarController+ShowHideBar.h:
#import <UIKit/UIKit.h>
@interface UITabBarController (ShowHideBar)
- (void) setHidden:(BOOL)hidden;
@end
用法:
[self.tabBarController setHidden:YES];
[self.tabBarController setHidden:NO];
【讨论】:
上面 Saurabh 的回答可以扩展到横向工作:
+ (void) hideTabBar:(UITabBarController *) tabbarcontroller {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
//Support for landscape views
int orientation = [[UIDevice currentDevice] orientation];
int x_pos = 480;
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
x_pos = 320;
}
for(UIView *view in tabbarcontroller.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view setFrame:CGRectMake(view.frame.origin.x, x_pos, view.frame.size.width, view.frame.size.height)];
}
else
{
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, x_pos)];
}
}
[UIView commitAnimations];
}
`
showTabBar() 对应的 x_pos 编号为 431 和 271。
【讨论】:
@karlbecker_com 答案适用于 iPhone 4 和 iPhone 5。如果有人遇到 iOS7 底部黑条的问题,请将 tabBarController 设置为半透明
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
// To Hide the black line in IOS7 only, this extra bit is required
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
[self.tabBarController.tabBar setTranslucent:YES];
}
【讨论】:
这是 karlbecker_com 的答案,已移植到 MonoTouch (Xamarin.iOS)。
唯一的区别是我在继承自 UITabBarController 的类上实现了方法,因此对“tabbarcontroller”的引用被替换为“this”。
public void HideTabBar()
{
var screenRect = UIScreen.MainScreen.Bounds;
float fHeight = screenRect.Height;
if(UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeLeft
|| UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeRight)
{
fHeight = screenRect.Width;
}
UIView.BeginAnimations(null);
UIView.SetAnimationDuration(0.4);
foreach(UIView view in this.View.Subviews)
{
if(view is UITabBar)
{
view.Frame = new RectangleF(view.Frame.X, fHeight, view.Frame.Width, view.Frame.Height);
}
else
{
view.Frame = new RectangleF(view.Frame.X, view.Frame.Y, view.Frame.Width, fHeight);
view.BackgroundColor = UIColor.Black;
}
}
UIView.CommitAnimations();
}
public void ShowTabBar()
{
var screenRect = UIScreen.MainScreen.Bounds;
float fHeight = screenRect.Height - 49f;
if(UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeLeft
|| UIApplication.SharedApplication.StatusBarOrientation == UIInterfaceOrientation.LandscapeRight)
{
fHeight = screenRect.Width - 49f;
}
UIView.BeginAnimations(null);
UIView.SetAnimationDuration(0.4);
foreach(UIView view in this.View.Subviews)
{
if(view is UITabBar)
{
view.Frame = new RectangleF(view.Frame.X, fHeight, view.Frame.Width, view.Frame.Height);
}
else
{
view.Frame = new RectangleF(view.Frame.X, view.Frame.Y, view.Frame.Width, fHeight);
}
}
UIView.CommitAnimations();
}
【讨论】:
自 IOS 7.1 起,“Swift” 解决方案:
self.tabBarController?.tabBar.hidden = true // hide tabbar
self.tabBarController?.tabBar.hidden = false // show tabbar
希望这能有所帮助!
【讨论】:
你可以推送一个模态视图控制器
[self presentModalViewController:myFullscreenViewController animated:YES];
这将在您当前的视图之上创建一个全新的全屏视图。
使用dismissModalViewController:animated: 关闭ist
【讨论】:
下面的解决方案在我必须使用 TabBar 动画切换到全屏模式的完全相同的用例中对我来说很好。
基本上,这个想法是
制作UITabBar的快照;
将快照的UIImage添加到与UITabBar具有相同帧的UIImageView;
李>调整底层视图的大小并将其放置在 self.tabBarController.view;
将 UITabBar 的 alpha 设置为 0.0;
将 UIImageView 与 UITabBar 的快照放在 self.tabBarController.view 上;
一旦完成上述操作,就可以做任何类型的动画
#import "QuartzCore/CALayer.h"
@implementation FTBFirstViewController {
BOOL hidden;
UIImageView *fakeTabBarImageView;
UIView *viewToResize;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//////////////////////////////
// Create your viewToResize
//////////////////////////////
[self.view addSubview:viewToResize];
hidden = NO;
}
- (void)hideTabBar:(id)sender {
if (!hidden) {
//
// to create the fake UITabBar
fakeTabBarImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
UIImage *fakeTabBarImage = [self imageScreenshotFromView:self.tabBarController.tabBar];
fakeTabBarImageView.image = fakeTabBarImage;
fakeTabBarImageView.frame = self.tabBarController.tabBar.frame;
//
// to resize underlying UIView
viewToResize.frame = (CGRect){viewToResize.frame.origin.x, viewToResize.frame.origin.y + 20.f, viewToResize.frame.size.width, viewToResize.frame.size.height + fakeTabBarImageView.frame.size.height};
//
// to hide real UITabBar
self.tabBarController.tabBar.alpha = 0.0;
//
// to add views in exactly this order
[self.tabBarController.view addSubview:viewToResize];
[self.tabBarController.view addSubview:fakeTabBarImageView];
//
// do any sort of animation
[UIView animateWithDuration:0.8 animations:^{
fakeTabBarImageView.frame = (CGRect){fakeTabBarImageView.frame.origin.x, fakeTabBarImageView.frame.origin.y + fakeTabBarImageView.frame.size.height, fakeTabBarImageView.frame.size};
}];
hidden = YES;
} else {
[UIView animateWithDuration:0.8 animations:^{
fakeTabBarImageView.frame = (CGRect){fakeTabBarImageView.frame.origin.x, fakeTabBarImageView.frame.origin.y - fakeTabBarImageView.frame.size.height, fakeTabBarImageView.frame.size};
} completion:^(BOOL complete){
self.tabBarController.tabBar.alpha = 1.0;
[fakeTabBarImageView removeFromSuperview];
fakeTabBarImageView = nil;
viewToResize.frame = self.view.frame;
[self.view addSubview:viewToResize];
[fakeTabBarImageView removeFromSuperview];
}];
hidden = NO;
}
}
- (UIImage *)imageScreenshotFromView:(UIView *)aView {
UIImage *viewImage;
UIGraphicsBeginImageContextWithOptions(aView.bounds.size, aView.opaque, [[UIScreen mainScreen] scale]);
[aView.layer renderInContext:UIGraphicsGetCurrentContext()];
viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return viewImage;
}
【讨论】:
我尝试了几乎所有这些答案,但没有一个对我有用。我的应用程序有一个 UITabBarController 作为根视图,每个选项卡都有一个 UINavigationController。 UINavigationControllers 之一有一个 UICollectionViewController 作为顶视图控制器。当用户在 UICollectionView 中选择一个项目时,我希望将详细视图控制器推送到导航堆栈上。然后我的详细视图底部有一个工具栏。我不希望工具栏出现在选项卡栏的顶部,因为这看起来很愚蠢,并且不需要从此视图切换选项卡上下文。我可以通过手动放置 UIToolbars 和 UITabBars 而不使用 UITabBarController 和内置 UIToolbar 来轻松解决这个问题,但这似乎重构太多,有点不雅。
最后,我的解决方案相当简单:将 UITabBarController 的边界扩展到屏幕底部。我将此添加到我的详细视图控制器中:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Extend the UITabBarController to shift the tab bar off screen
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGRect tabBarControllerFrame = self.tabBarController.view.frame;
if (animated) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
tabBarControllerFrame.size.height = screenRect.size.height +
self.tabBarController.tabBar.frame.size.height;
[self.tabBarController.view setFrame:tabBarControllerFrame];
[UIView commitAnimations];
}
else {
tabBarControllerFrame.size.height = screenRect.size.height +
self.tabBarController.tabBar.frame.size.height;
[self.tabBarController.view setFrame:tabBarControllerFrame];
}
// Now show the toolbar
[self.navigationController setToolbarHidden:NO animated:animated];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Ensure the UITabBarController remains extended when subviews are laid out
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGRect tabBarControllerFrame = self.tabBarController.view.frame;
tabBarControllerFrame.size.height = screenRect.size.height +
self.tabBarController.tabBar.frame.size.height;
[self.tabBarController.view setFrame:tabBarControllerFrame];
}
然后当用户弹回到我的 UINavigationController 顶部时重新显示标签栏,我将它添加到我的顶视图控制器中:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Hide toolbar
[self.navigationController setToolbarHidden:YES animated:animated];
// Tab bar back on to screen
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGRect tabBarControllerFrame = self.tabBarController.view.frame;
if (tabBarControllerFrame.size.height != screenRect.size.height) {
if (animated) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
tabBarControllerFrame.size.height = screenRect.size.height;
[self.tabBarController.view setFrame:tabBarControllerFrame];
[UIView commitAnimations];
}
else {
tabBarControllerFrame.size.height = screenRect.size.height;
[self.tabBarController.view setFrame:tabBarControllerFrame];
}
}
}
【讨论】:
在 iOS8 中,只需设置 tabBar 的 hidden 属性就足够了
就像在 Swift 中一样,你可以
rootTabVC = UITabBarController()
rootTabVC?.tabBar.hidden = true
我在appdelegate 中的didFinishLaunchingWithOptions 中执行此操作,并且效果很好,我想如果我在旧iOS 版本中没记错的话,您还需要将tabBar 的frame 设置为屏幕,否则tabbar 不会显示,但仍会占用空间。
【讨论】:
@Saurabh 代码的 Swift 和修改版本
方法
func setTabBarHidden (bool:Bool){
for view in tabBarController!.view.subviews {
if (view.isKindOfClass(UITabBar)){
let tabBar = view as! UITabBar
UIView.animateWithDuration(0.3, animations: { () -> Void in
var offset = CGFloat(50)
if (bool == false){
offset = -50;
}
tabBar.frame = CGRect(origin: CGPointMake(tabBar.frame.origin.x, tabBar.frame.origin.y + offset), size: tabBar.frame.size)
})
}
}
}
展示
override func viewDidLoad() {
setTabBarHidden(true)
}
隐藏
override func viewWillDisappear(animated: Bool) {
setTabBarHidden(false)
}
【讨论】:
一个带有动画的swift版本,你需要自己设置一个属性isHideTabBar。
self.isHideTabBar = !self.isHideTabBar
UIView.animate(withDuration: 0.5, animations: {
self.tabBarController?.tabBar.frame = (self.tabBarController?.tabBar.frame.offsetBy(dx: 0, dy: self.isHideTabBar ? 100 : -100))!
})
【讨论】:
已更新并适用于 swift 5 和 ios 14.0
/*
Shows or hides the tabbar
:param: hidden whether to show or hide the tabbar
:param: animationDuration the animation's duration
*/
extension UITabBarController {
func setHidden(hidden:Bool, animationDuration:TimeInterval = 0.25) {
let screenRect = UIScreen.main.bounds
var fHeight = screenRect.size.height
if !hidden {
fHeight -= self.tabBar.frame.size.height
}
UIView.animate(withDuration: animationDuration, animations: {
for view in self.view.subviews {
if view is UITabBar {
view.frame = CGRect(
x: view.frame.origin.x,
y: fHeight,
width: view.frame.size.width,
height: view.frame.size.height)
}
}
})
}
}
这是一个更直接的端口(未测试):
/*
Shows or hides the tabbar
:param: hidden whether to show or hide the tabbar
:param: animationDuration the animation's duration
*/
extension UITabBarController {
func setHidden(hidden:Bool, animationDuration:TimeInterval = 0.25) {
let screenRect = UIScreen.main.bounds
var fHeight = screenRect.size.height
if UIApplication.shared.statusBarOrientation.isLandscape {
fHeight = screenRect.size.width
}
if !hidden {
fHeight -= self.tabBar.frame.size.height
}
UIView.animate(withDuration: animationDuration, animations: {
for view in self.view.subviews {
if view is UITabBar {
view.frame = CGRect(
x: view.frame.origin.x,
y: fHeight,
width: view.frame.size.width,
height: view.frame.size.height)
}
else if hidden {
view.frame = CGRect(
x: view.frame.origin.x,
y: view.frame.origin.y,
width: view.frame.size.width,
height: fHeight)
}
}
}, completion: { finished in
if !hidden {
UIView.animate(withDuration: animationDuration, animations: {
for view in self.view.subviews {
if !(view is UITabBar) {
view.frame = CGRect(
x: view.frame.origin.x,
y: view.frame.origin.y,
width: view.frame.size.width,
height: fHeight)
}
}
})
}
})
}
}
【讨论】:
隐藏标签栏不是一个合适的解决方案,它不会调整当前视图控制器的视图高度。
相反,您可以简单地转换标签栏本身,或者通过它的高度(隐藏)或身份转换以重置为可见。
extension UITabBarController {
func setBarHiddenAnimated(_ hidden:Bool) {
UIView.animate(withDuration: 0.3, animations: {
if hidden {
self.tabBar.transform = CGAffineTransform(translationX: 0, y: self.tabBar.frame.size.height)
} else {
self.tabBar.transform = CGAffineTransform.identity
}
})
}
}
请注意,您可能需要将视图控制器设置为“在底栏下方延伸”和“在不透明栏下方延伸”以在动画期间移除黑色背景。
【讨论】: