Кнопка изменения назад в 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 "проведите по экрану слева направо", чтобы перейти к предыдущему контроллеру. Кто-нибудь знает, как я могу настроить пользовательскую кнопку и все равно сохранить этот жест включенным?
EDIT:
Я попытался установить viewController.navigationItem.backBarButtonItem, но это, похоже, не показывает мой пользовательский образ.
Ответы
Ответ 1
ВАЖНО:
Это взломать. Я бы рекомендовал взглянуть на этот ответ.
Вызов следующей строки после назначения leftBarButtonItem
работал у меня:
self.navigationController.interactivePopGestureRecognizer.delegate = self;
Edit:
Это не работает, если вызывается в методах init
. Его следует вызывать в viewDidLoad
или аналогичных методах.
Ответ 2
Используйте свойства 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 приведет к множеству проблем.
Ответ 3
Я увидел это решение 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
Ответ 4
Я использую
[[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"nav_back.png"]];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"nav_back.png"]];
[UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault];
Ответ 5
Я также скрываю кнопку "Назад", заменяя ее пользовательским элементом leftBarItem.
Удаление делегата 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;
}
Ответ 6
navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
Это от http://stuartkhall.com/posts/ios-7-development-tips-tricks-hacks, но вызывает несколько ошибок:
- Нажмите другой viewController в navigationController при прокрутке с левого края экрана;
- Или, проведите пальцем по левому краю экрана, когда topViewController выскочит из навигационного контроллера;
например. Когда появится rootViewController of navigationController, проведите пальцем по левому краю экрана и нажмите что-нибудь (БЫСТРО), чтобы нажать anotherViewController в navigationController, затем
- rootViewController не отвечает на какое-либо событие касания;
- Другой_ViewController не будет отображаться;
- Снова проведите по краю экрана, будет показан другой элемент управленияView:
- Коснитесь пользовательской кнопки "назад", чтобы вызвать другой диспетчер проверки, сбой!
Итак, вы должны реализовать метод UIGestureRecognizerDelegate
в self.navigationController.interactivePopGestureRecognizer.delegate
следующим образом:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer == navigationController.interactivePopGestureRecognizer) {
return !navigationController.<#TODO: isPushAnimating#> && [navigationController.viewControllers count] > 1;
}
return YES;
}
Ответ 7
Вот версия Nick 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 {}
Ответ 8
Попробуйте self.navigationController.
interactivePopGestureRecognizer
.enabled = YES;
Ответ 9
Я не писал этого, но следующий блог очень помог и решил мои проблемы с пользовательской кнопкой навигации:
http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/
Таким образом, он реализует пользовательский UINavigationController, который использует делегат по умолчанию. Очень чистый и портативный!
код:
@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;
}
Ответ 10
У меня была аналогичная проблема, когда я назначал текущий контроллер представления в качестве делегата для интерактивного пота, но нарушал бы жест при любых просмотренных представлениях или представлениях под представлением в стеке навигации. То, как я решил это, - установить делегат в -viewDidAppear
, а затем установить его на nil в -viewWillDisappear
. Это позволило моим другим представлениям работать правильно.
Ответ 11
Представьте, что мы используем шаблон проекта мастера/детали Apple по умолчанию, где master является контроллером табличного представления, а нажатие на него отображает контроллер подробного представления.
Мы хотим настроить кнопку "Назад", которая появляется в контроллере подробного представления. Вот как настроить изображение, цвет изображения, текст, цвет текста и font кнопки "Назад".
Чтобы изменить изображение, цвет изображения, цвет текста или шрифт глобально, поместите следующее в местоположение, которое называется , прежде чем какой-либо из ваших контроллеров представлений будет создан (например, 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 после установки self.navigationItem.backBarButtonItem не работает, поэтому они должны быть установлены до того, как вы присвоите значение этому свойству.
Ответ 12
Создайте класс "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
}}