Ich habe eine iOS 7-App, in der ich eine benutzerdefinierte Zurück-Schaltfläche wie folgt einstelle:
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;
Dadurch wird jedoch die iOS 7-Geste "Von links nach rechts wischen" deaktiviert, um zum vorherigen Controller zu navigieren. Weiß jemand, wie ich eine benutzerdefinierte Schaltfläche festlegen und diese Geste trotzdem aktivieren kann?
BEARBEITEN: Ich habe versucht, stattdessen viewController.navigationItem.backBarButtonItem festzulegen, aber dies scheint mein benutzerdefiniertes Bild nicht anzuzeigen.
Antworten:
WICHTIG: Dies ist ein Hack. Ich würde empfehlen, sich diese Antwort anzuschauen .
Aufruf der folgenden Zeile nach Zuweisung der
leftBarButtonItem
für mich bearbeiteten:self.navigationController.interactivePopGestureRecognizer.delegate = self;
Bearbeiten: Dies funktioniert nicht, wenn
init
Methoden aufgerufen werden. Es sollte inviewDidLoad
oder ähnlichen Methoden aufgerufen werden.quelle
self
ihn von einem Klassenobjekt entfernt_UINavigationInteractiveTransition
. Es liegt in der Verantwortung dieses Objekts, sicherzustellen, dass der Navigationscontroller nicht angewiesen wird, während des Übergangs zu platzen. Es wird noch untersucht, ob es möglich ist, diese Geste zu aktivieren, wenn die Zurück-Schaltfläche benutzerdefiniert ist.Verwenden Sie nach Möglichkeit die Eigenschaften backIndicatorImage und backIndicatorTransitionMaskImage der UINavigationBar. Wenn Sie diese auf einem UIAppearanceProxy festlegen, können Sie das Verhalten in Ihrer Anwendung problemlos ändern. Die Falte ist, dass Sie diese nur auf ios 7 einstellen können, aber das funktioniert, weil Sie die Pop-Geste sowieso nur auf ios 7 verwenden können. Ihr normales ios 6-Styling kann intakt bleiben.
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 }
Der Versuch, den Delegierten des interaktiven PopGestureRecognizers zu manipulieren, führt zu vielen Problemen.
quelle
topViewController
.ABPeoplePickerNavigationController
Ihnen erstellt wurden , können Sie eine benutzerdefinierteUINavigationController
Unterklasse verwenden:[[UINavigationBar appearanceWhenContainedIn:[THNavigationController class], nil] setBackIndicatorImage:[UIImage imageNamed:@"btn_back_arrow"]];
[[UINavigationBar appearanceWhenContainedIn:[THNavigationController class], nil] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"btn_back_arrow_highlighted"]];
Ich habe diese Lösung gesehen http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/, die UINavigationController unterordnet. Dies ist eine bessere Lösung, da es den Fall behandelt, in dem Sie wischen, bevor der Controller installiert ist - was zu einem Absturz führt.
Außerdem ist mir aufgefallen, dass die Benutzeroberfläche nicht mehr reagiert, wenn Sie auf dem Root-View-Controller wischen (nachdem Sie einen gedrückt haben und wieder zurück) (auch das gleiche Problem in der obigen Antwort).
Der Code im untergeordneten UINavigationController sollte also folgendermaßen aussehen:
@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
quelle
ich benutze
[[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"nav_back.png"]]; [[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"nav_back.png"]]; [UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault];
quelle
Ich verstecke auch die Zurück-Schaltfläche und ersetze sie durch ein benutzerdefiniertes leftBarItem.
Das Entfernen des InteractivePopGestureRecognizer-Delegaten nach einer Push-Aktion hat bei mir funktioniert:
[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; }
quelle
navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
Dies ist von http://stuartkhall.com/posts/ios-7-development-tips-tricks-hacks , verursacht aber mehrere Fehler:
Wenn beispielsweise der rootViewController von navigationController angezeigt wird, wischen Sie vom linken Bildschirmrand nach innen und tippen Sie auf etwas (SCHNELL), um einen anderen ViewController in den Navigationscontroller zu verschieben
Sie müssen die
UIGestureRecognizerDelegate
Methode also folgendermaßen implementierenself.navigationController.interactivePopGestureRecognizer.delegate
:- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer == navigationController.interactivePopGestureRecognizer) { return !navigationController.<#TODO: isPushAnimating#> && [navigationController.viewControllers count] > 1; } return YES; }
quelle
Hier ist die swift3-Version der Antwort von 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 {}
quelle
Versuchen
self.navigationController.
interactivePopGestureRecognizer
.enabled = YES;
quelle
Ich habe dies nicht geschrieben, aber der folgende Blog hat mir sehr geholfen und meine Probleme mit der benutzerdefinierten Navigationsschaltfläche gelöst:
http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/
Zusammenfassend implementiert er einen benutzerdefinierten UINavigationController, der den Pop-Gesten-Delegaten verwendet. Sehr sauber und tragbar!
Code:
@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; }
Bearbeiten. Korrektur für Probleme hinzugefügt, wenn ein Benutzer versucht, auf einem Root-View-Controller nach links zu wischen:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)] && self.topViewController == [self.viewControllers firstObject] && gestureRecognizer == self.interactivePopGestureRecognizer) { return NO; } return YES; }
quelle
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 {}
quelle
Verwenden Sie diese Logik, um die Wischgeste weiterhin zu aktivieren oder zu deaktivieren.
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { if (self.navigationController.viewControllers.count > 1) { self.navigationController.interactivePopGestureRecognizer.enabled = YES; } else { self.navigationController.interactivePopGestureRecognizer.enabled = NO; } } }
quelle
Ich hatte ein ähnliches Problem, bei dem ich den aktuellen Ansichts-Controller als Delegaten für die interaktive Pop-Geste zuwies, die Geste jedoch bei allen Ansichten oder Ansichten unter der Ansicht im Navigationsstapel unterbrach. Die Art und Weise, wie ich das gelöst habe, bestand darin, den Delegaten
-viewDidAppear
einzuschalten und ihn dann auf Null zu setzen-viewWillDisappear
. Dadurch konnten meine anderen Ansichten korrekt funktionieren.quelle
Stellen Sie sich vor, wir verwenden die Standard-Master- / Detailprojektvorlage von Apple, bei der master ein Controller für die Tabellenansicht ist. Wenn Sie darauf tippen, wird der Controller für die Detailansicht angezeigt.
Wir möchten die Schaltfläche "Zurück" anpassen, die im Detailansichts-Controller angezeigt wird. Auf diese Weise können Sie das Bild , die Bildfarbe , den Text , die Textfarbe und die Schriftart der Schaltfläche "Zurück" anpassen .
Um das Bild, die Bildfarbe, die Textfarbe oder die Schriftart global zu ändern, platzieren Sie Folgendes an einem Ort, der aufgerufen wird, bevor einer Ihrer Ansichts-Controller erstellt wird (z. B.
application:didFinishLaunchingWithOptions:
ein guter Ort).- (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; }
Beachten Sie
appearanceWhenContainedIn:
, dass Sie mehr Kontrolle darüber haben können, welche Ansichtscontroller von diesen Änderungen betroffen sind. Beachten Sie jedoch, dass Sie nicht übergeben können[DetailViewController class]
, da sie in einem UINavigationController und nicht in Ihrem DetailViewController enthalten sind. Dies bedeutet, dass Sie UINavigationController in Unterklassen unterteilen müssen, wenn Sie mehr Kontrolle darüber haben möchten, was betroffen ist.Um den Text oder die Schriftart / Farbe eines bestimmten Elements der Zurück-Schaltfläche anzupassen, müssen Sie dies im MasterViewController tun (nicht im DetailViewController!). Dies scheint nicht intuitiv zu sein, da die Schaltfläche im DetailViewController angezeigt wird. Sobald Sie jedoch verstanden haben, dass das Anpassen durch Festlegen einer Eigenschaft in einem Navigationselement sinnvoller wird.
- (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; }
Hinweis: Der Versuch, die titleTextAttributes nach dem Festlegen von self.navigationItem.backBarButtonItem festzulegen, scheint nicht zu funktionieren. Sie müssen daher festgelegt werden, bevor Sie den Wert dieser Eigenschaft zuweisen.
quelle
Erstellen Sie eine Klasse 'TTNavigationViewController', die zur Unterklasse von 'UINavigationController' gehört, und erstellen Sie Ihren vorhandenen Navigationscontroller dieser Klasse entweder in Storyboard / Klasse, Beispielcode in Klasse -
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 }}
quelle