Как скрыть панель вкладок с анимацией в 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, на контроллере вида назначения просто установите этот флажок:
в соответствии с 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 без подклассов и, следовательно, расширение возможно (расширения не позволяют хранить свойства)
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.