Изменять кнопки в iOS 7 отключить свайп для перехода обратно
У меня есть приложение iOS 7, где я устанавливаю пользовательскую кнопку Назад следующим образом:
UIImage *backButtonImage = [UIImage imageNamed:@"back-button"];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setImage:backButtonImage forState:UIControlStateNormal];
backButton.frame = CGRectMake(0, 0, 20, 20);
[backButton addTarget:self
action:@selector(popViewController)
forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
viewController.navigationItem.leftBarButtonItem = backBarButtonItem;
но это отключает iOS 7 "проведите пальцем слева направо" жест для перехода к предыдущему контроллеру. Кто-нибудь знает, как я могу создать пользовательскую кнопку и сохранить этот жест включен?
изменить: Я попытался установить viewController.navigationItem.backBarButtonItem вместо этого, но это, кажется, не показывает мой пользовательский образ.
13 ответов:
важно: Это хак. Я бы рекомендовал взглянуть на это ответ.
вызов следующей строки после назначения
leftBarButtonItem
работала на меня:self.navigationController.interactivePopGestureRecognizer.delegate = self;
Edit: Это не работает, если вызывается в
init
методы. Он должен быть вызван вviewDidLoad
или аналогичные методы.
используйте свойства backIndicatorImage и backIndicatorTransitionMaskImage панели UINavigationBar, если это вообще возможно. Установка их на UIAppearanceProxy может легко изменить поведение в вашем приложении. Морщина заключается в том, что вы можете установить их только на ios 7, но это работает, потому что вы можете использовать только поп-жест на ios 7 в любом случае. Ваш обычный стиль ios 6 может остаться нетронутым.
UINavigationBar* appearanceNavigationBar = [UINavigationBar appearance]; //the appearanceProxy returns NO, so ask the class directly if ([[UINavigationBar class] instancesRespondToSelector:@selector(setBackIndicatorImage:)]) { appearanceNavigationBar.backIndicatorImage = [UIImage imageNamed:@"back"]; appearanceNavigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"]; //sets back button color appearanceNavigationBar.tintColor = [UIColor whiteColor]; }else{ //do ios 6 customization }
попытка манипулировать делегатом interactivePopGestureRecognizer будет это приводит к множеству проблем.
Я видел это решение http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/ Какие подклассы UINavigationController. Это лучшее решение, поскольку оно обрабатывает случай, когда вы проводите пальцем до того, как контроллер находится на месте, что вызывает сбой.
в дополнение к этому я заметил, что если вы делаете салфетки на контроллере корневого представления (после нажатия на один и обратно), пользовательский интерфейс перестает отвечать (также та же проблема в ответе выше).
Так код подкласс UINavigationController должен выглядеть так:
@implementation NavigationController - (void)viewDidLoad { [super viewDidLoad]; __weak NavigationController *weakSelf = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = weakSelf; self.delegate = weakSelf; } } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { // Hijack the push method to disable the gesture if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.enabled = NO; } [super pushViewController:viewController animated:animated]; } #pragma mark - UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { // Enable the gesture again once the new controller is shown self.interactivePopGestureRecognizer.enabled = ([self respondsToSelector:@selector(interactivePopGestureRecognizer)] && [self.viewControllers count] > 1); } @end
Я использую
[[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"nav_back.png"]]; [[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"nav_back.png"]]; [UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault];
Я также скрываю кнопку Назад, заменяя ее пользовательским левым баритемом.
Удаление делегата interactivePopGestureRecognizer после действия push сработало для меня:[self.navigationController pushViewController:vcToPush animated:YES]; // Enabling iOS 7 screen-edge-pan-gesture for pop action if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.delegate = nil; }
navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
это от http://stuartkhall.com/posts/ios-7-development-tips-tricks-hacks, но это вызывает несколько ошибок:
- нажмите другой viewController в navigationController при прокрутке с левого края экрана;
- или проведите пальцем от левого края экрана, когда topViewController выскакивает из navigationController;
например, когда rootViewController navigationController является показывая, проведите пальцем от левого края экрана и нажмите что-то (быстро), чтобы нажать anotherViewController в navigationController, затем
- rootViewController не отвечает на любое событие касания;
- anotherViewController не будет отображаться;
- проведите пальцем от края экрана снова, anotherViewController будет показан;
- Нажмите кнопку "назад", чтобы открыть anotherViewController, аварии!
так что вы должны реализовать
UIGestureRecognizerDelegate
методself.navigationController.interactivePopGestureRecognizer.delegate
такой:- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer == navigationController.interactivePopGestureRecognizer) { return !navigationController.<#TODO: isPushAnimating#> && [navigationController.viewControllers count] > 1; } return YES; }
вот swift3 версия ответ Ника H247
class NavigationController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() if responds(to: #selector(getter: interactivePopGestureRecognizer)) { interactivePopGestureRecognizer?.delegate = self delegate = self } } override func pushViewController(_ viewController: UIViewController, animated: Bool) { if responds(to: #selector(getter: interactivePopGestureRecognizer)) { interactivePopGestureRecognizer?.isEnabled = false } super.pushViewController(viewController, animated: animated) } } extension NavigationController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { interactivePopGestureRecognizer?.isEnabled = (responds(to: #selector(getter: interactivePopGestureRecognizer)) && viewControllers.count > 1) } } extension NavigationController: UIGestureRecognizerDelegate {}
попробовать
self.navigationController.
interactivePopGestureRecognizer
.enabled = YES;
Я этого не писал, но следующий блог очень помог и решил мои проблемы с пользовательской кнопкой навигации:
http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/
таким образом, он реализует пользовательский UINavigationController, который использует делегат Pop gesture. Очень чистый и портативный!
код:
@interface CBNavigationController : UINavigationController <UINavigationControllerDelegate, UIGestureRecognizerDelegate> @end @implementation CBNavigationController - (void)viewDidLoad { __weak CBNavigationController *weakSelf = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = weakSelf; self.delegate = weakSelf; } } // Hijack the push method to disable the gesture - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = NO; [super pushViewController:viewController animated:animated]; } #pragma mark UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { // Enable the gesture again once the new controller is shown if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = YES; }
правка. Добавлено исправление проблем, когда пользователь пытается прокрутить влево на корневом представлении контроллер:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)] && self.topViewController == [self.viewControllers firstObject] && gestureRecognizer == self.interactivePopGestureRecognizer) { return NO; } return YES; }
RootView
override func viewDidAppear(_ animated: Bool) { self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false }
ChildView
override func viewDidLoad() { self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true self.navigationController?.interactivePopGestureRecognizer?.delegate = self } extension ChildViewController: UIGestureRecognizerDelegate {}
у меня была аналогичная проблема, когда я назначал текущий контроллер представления в качестве делегата для интерактивного поп-жеста, но нарушил бы жест на любые представления, которые были нажаты, или представления под представлением в стеке навигации. Способ, которым я решил это, состоял в том, чтобы установить делегат в
-viewDidAppear
, затем установите его в ноль в-viewWillDisappear
. Это позволило моим другим взглядам работать правильно.
представьте, что мы используем шаблон проекта Apple по умолчанию master/detail, где master-это контроллер табличного представления, и нажатие на него покажет контроллер подробного представления.
мы хотим настроить кнопку Назад, которая появляется в деталь-представление-контроллер. Это как настроить изображения,цветного изображения,текст, цвет текста, и шрифт кнопки "Назад".
чтобы изменить изображение, цвет изображения, цвет текста или шрифт глобально, поместите следующее в место, которое называется перед созданием любого из ваших контроллеров вида (например,
application:didFinishLaunchingWithOptions:
- это хорошее место).- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UINavigationBar* navigationBarAppearance = [UINavigationBar appearance]; // change the back button, using default tint color navigationBarAppearance.backIndicatorImage = [UIImage imageNamed:@"back"]; navigationBarAppearance.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"]; // change the back button, using the color inside the original image navigationBarAppearance.backIndicatorImage = [[UIImage imageNamed:@"back"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; navigationBarAppearance.backIndicatorTransitionMaskImage = [UIImage imageNamed:@"back"]; // change the tint color of everything in a navigation bar navigationBarAppearance.tintColor = [UIColor greenColor]; // change the font in all toolbar buttons NSDictionary *barButtonTitleTextAttributes = @{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:12.0], NSForegroundColorAttributeName: [UIColor purpleColor] }; [[UIBarButtonItem appearance] setTitleTextAttributes:barButtonTitleTextAttributes forState:UIControlStateNormal]; return YES; }
Примечание, Вы можете использовать
appearanceWhenContainedIn:
чтобы иметь больше контроля над тем, какой вид контроллеров затронутых этими изменениями, но имейте в виду, что вы не можете пройти[DetailViewController class]
, потому что он содержится внутри UINavigationController, а не ваш DetailViewController. Это означает, что вам нужно будет подкласс UINavigationController если вы хотите больше контроля над тем, что влияет.чтобы настроить текст или шрифт / цвет определенного элемента кнопки назад, вы должны сделать это в MasterViewController (не DetailViewController!). Это кажется неинтуитивным, потому что кнопка появляется на DetailViewController. Однако, как только вы поймете, что способ настроить его-это установить свойство на navigationItem, это начинает иметь больше смысла.
- (void)viewDidLoad { // MASTER view controller [super viewDidLoad]; UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:@"Testing" style:UIBarButtonItemStylePlain target:nil action:nil]; NSDictionary *barButtonTitleTextAttributes = @{ NSFontAttributeName: [UIFont fontWithName:@"HelveticaNeue-Light" size:12.0], NSForegroundColorAttributeName: [UIColor purpleColor] }; [buttonItem setTitleTextAttributes:barButtonTitleTextAttributes forState:UIControlStateNormal]; self.navigationItem.backBarButtonItem = buttonItem; }
Примечание.: при попытке установить titleTextAttributes после установки самостоятельно.navigationItem.backBarButtonItem, похоже, не работает, поэтому они должны быть установлены перед присвоением значения этому свойству.
создайте класс 'TTNavigationViewController' который является подклассом 'UINavigationController' и сделайте свой существующий навигационный контроллер этого класса либо в раскадровке / классе, пример кода в классе -
class TTNavigationViewController: UINavigationController, UIGestureRecognizerDelegate { override func viewDidLoad() { super.viewDidLoad() self.setNavigationBarHidden(true, animated: false) // enable slide-back if self.responds(to: #selector(getter: UINavigationController.interactivePopGestureRecognizer)) { self.interactivePopGestureRecognizer?.isEnabled = true self.interactivePopGestureRecognizer?.delegate = self } } func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return true }}