Правильный способ скрыть строку состояния в iOS, с анимацией и изменением размера корневого представления
Рассмотрим контроллер вида, который должен выскочить (или скрыть) строку состояния при нажатии кнопки.
- (void) buttonClick:(id)sender
{
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
}
Вышеописанное эффективно скрывает строку состояния, но не изменяет размер корневого представления соответствующим образом, оставляя 20-пиксельный зазор сверху.
Я ожидал, что корневой вид будет расширяться в пространстве, которое ранее использовалось в строке состояния (анимированное, с той же продолжительностью, что и анимация строки состояния).
Каков правильный способ сделать это?
(Я знаю, что есть много похожих вопросов, но я не мог найти ни одного скрытия строки состояния по требованию, а не скрывать его, чтобы отобразить новый контроллер представления)
Подход "грубой силы"
Очевидно, что следующие работы...
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.view.frame;
frame.origin.y -= 20;
frame.size.height += 20;
self.view.frame = frame;
}];
... но имеет недостатки:
- Жесткие коды: продолжительность анимации слайдов
- Жестко кодирует высоту строки состояния
- Начало корневого представления остается на (0, -20). Мне нравятся мои кадры для начала (0,0), когда это возможно.
Что я уже пробовал
- Убедитесь, что маска авторазрешения корневого представления имеет
UIViewAutoresizingFlexibleTopMargin
и UIViewAutoresizingFlexibleHeight
.
- Вызывается
[self.view setNeedsLayout]
после скрытия строки состояния.
- Вызывается
[self.view setNeedsDisplay]
после скрытия строки состояния.
- Установите
wantsFullScreenLayout
в YES
до и после скрытия строки состояния.
Ответы
Ответ 1
Это прекрасно работает и не имеет ничего жестко закодированного.
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
self.navigationController.navigationBar.frame = self.navigationController.navigationBar.bounds;
self.view.window.frame = CGRectMake(0, 0, appFrame.size.width, appFrame.size.height);
}];
Ответ 2
Для тех, кто пытается реализовать это с появлением строки состояния на основе контроллера, вам необходимо реализовать метод prefersStatusBarHidden в контроллере просмотра
- (BOOL)prefersStatusBarHidden
{
// If self.statusBarHidden is TRUE, return YES. If FALSE, return NO.
return (self.statusBarHidden) ? YES : NO;
}
И затем в методе нажатия кнопки:
- (void) buttonClick:(id)sender
{
// Switch BOOL value
self.statusBarHidden = (self.statusBarHidden) ? NO : YES;
// Update the status bar
[UIView animateWithDuration:0.25 animations:^{
[self setNeedsStatusBarAppearanceUpdate];
}];
}
Чтобы установить стиль анимации, вы используете это:
-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
return UIStatusBarAnimationSlide;
}
И чтобы настроить стиль:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
Ответ 3
Вы можете представить и затем отклонить контроллер модального просмотра, чтобы скрыть строку состояния правильно
- (void)toggleStatusBar {
BOOL isStatusBarHidden = [[UIApplication sharedApplication] isStatusBarHidden];
[[UIApplication sharedApplication] setStatusBarHidden:!isStatusBarHidden];
UIViewController *vc = [[UIViewController alloc] init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
[vc release];
}
Я использовал этот код в методе "willAnimateRotationToInterfaceOrientation" для альбомной ориентации, и все работает правильно. Но я не знаю, будет ли это работать с анимацией.
Ответ 4
Скрыть или показать строку состояния, которая также изменяет размеры представления:
-(void)statusBar:(BOOL)status {
UIViewController *rootViewController = self.view.window.rootViewController;
UIView *view = rootViewController.view;
// Hide/Unhide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:status]; // BOOL : YES or NO
// statusBar frame
CGRect statusBarFrame = [UIApplication.sharedApplication statusBarFrame];
// Establish baseline frame
CGRect newViewFrame = self.view.window.bounds;
// Check statusBar frame is worth dodging
if (!CGRectEqualToRect(statusBarFrame, CGRectZero)) {
UIInterfaceOrientation currentOrientation = rootViewController.interfaceOrientation;
if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
// If portrait need to shrink height
newViewFrame.size.height -= statusBarFrame.size.height;
if (currentOrientation == UIInterfaceOrientationPortrait) {
// If not upside-down move down origin
newViewFrame.origin.y += statusBarFrame.size.height;
}
} else { // Is landscape
// portrait shrink width
newViewFrame.size.width -= statusBarFrame.size.width;
if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
// If the status bar is on the left side of the window move origin
newViewFrame.origin.x += statusBarFrame.size.width;
}
}
}
view.frame = newViewFrame; // pass new frame
}
метод вызова (сообщение):
if ([[UIApplication sharedApplication] isStatusBarHidden]) {
[self statusBar:NO];
} else {
[self statusBar:YES];
}
Ответ 5
Я знаю, что это так, но недостатки также очевидны. Вы можете установить self.wantsFullScreenLayout = YES;
в свой viewDidLoad
и установить xib файл размером с экран (320x480 и 320x568 для iPhone5). Но это означает, что область под строкой состояния также не видна. И используя этот способ, ваше представление также не будет расширяться при скрытии строки состояния. Вы можете рассмотреть этот путь, если у вас нет чего-то отображаемого в области строки состояния.
Ответ 6
После траты часов эксперимента и поиска ответа; в частности этот ответ. С небольшой настройкой, я успешно сделал это, теперь верхний зазор 20px пропал между переходами!
Предположим, что у нас есть BOOL isStatusBarEnabled
ivar, который укажет, нужно ли скрывать строку состояния или нет (например: при доступе к NSUserDefault
для проверки boolValueForKey
).
Итак, сначала проверяем, является ли статусBar уже скрытым или нет через [[UIApplication sharedApplication] isStatusBarHidden]
, если он не скрыт (== отображается), мы его спрячем! Иначе, действуйте иначе!
-
Чтобы исправить 20px при отображении статуса, но навигация не будет правильно нажата, просто добавьте 20 пунктов к origin.y
из self.navgigationController.navigationBar.frame
.
-
Сделайте то же самое, когда мы хотим скрыть строку состояния, просто удалите 20 пунктов в origin.y
из self.navgigationController.navigationBar.frame
, поэтому просто оставьте это 0
.
вот оно!
@implementation SomeViewController {
BOOL isStatusBarEnabled;
}
// ...
- (void)toggleStatusBar
{
UINavigationBar *navBar = self.navigationController.navigationBar;
if ([[UIApplication sharedApplication] isStatusBarHidden]) {
// Change to regular mode
// Show status bar
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.3
animations:^{
navBar.frame = CGRectMake(navBar.frame.origin.x, 20, navBar.frame.size.width, navBar.frame.size.height);
} completion:nil];
} else if (![[UIApplication sharedApplication] isStatusBarHidden]) {
// Change to fullscreen mode
// Hide status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.4
animations:^{
navBar.frame = CGRectMake(navBar.frame.origin.x, 0, navBar.frame.size.width, navBar.frame.size.height);
} completion:nil];
}
}
// ...
... тогда, в моем случае, у меня есть ключ настройки, чтобы пользователь мог выбрать отображение/скрытие строки состояния.
// ...
- (void)onDefaultsChanged:(NSNotification*)aNotification
{
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
isStatusBarEnabled = [standardDefaults boolForKey:kStatusBar];
if (isStatusBarEnabled) {
if ([[UIApplication sharedApplication] isStatusBarHidden]) {
// Change to regular mode
// Show status bar
[self toggleStatusBar];
} else {
// Change to fullscreen mode
// Hide status bar
[self toggleStatusBar];
}
// ...
}
что это!