38 votes

Bouton de retour personnalisé d'iOS 7

Je veux utiliser un bouton de retour personnalisé. Dans iOS 6, tout est parfait mais iOS 7 est étrange.

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:[[UIImage imageNamed:@"back_button_normal"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12.0, 0, 12.0)] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

D'abord, il n'y a pas de flèche iOS 7 ni d'image de fond.

(en russe)

initial state

puis, si vous appuyez sur le bouton, l'image de fond apparaît. J'avais également défini une image de fond pour UIControlStateHighlighted et lorsque vous maintenez le bouton enfoncé, l'image en surbrillance apparaît également. Après avoir appuyé sur n'importe quel bouton de retour, tous les boutons de retour ont une image de fond.

once pressed

MAIS, si vous présentez un contrôleur de vue modal, que vous l'écartez, puis que vous faites passer n'importe quel contrôleur de vue iOS 7 Une flèche apparaîtra sur chaque bouton de retour.

J'utilise le DP5. Est-ce un bug d'UIKit ?

PS J'ai également essayé de créer un bouton de retour manuellement, en utilisant UIBarButtonItem et définir l'image de fond, puis self.navigationItem.backBarButtonItem = barButtonItem; N'a pas aidé. J'ai ensuite essayé de mettre l'image d'arrière-plan à l'état désactivé et de changer la propriété activée de mon bouton de barre, mais cela n'a pas aidé non plus.

enter image description here

50voto

B.S. Points 5782

Ce n'est pas un bug, c'est comment Back button semble dans iOS 7. Par exemple :

enter image description here

Vous devriez probablement utiliser le nouveau concept pour votre application, et ne pas définir l'image d'arrière-plan pour le bouton retour dans iOS 7.

Si vous voulez toujours que votre bouton de retour soit identique à ce qu'il était dans iOS6, vous devriez probablement créer ces boutons de retour manuellement :

- (void)loadView
{
    [super loadView];

    UIButton *backButton = [[UIButton alloc] initWithFrame: CGRectMake(0, 0, 60.0f, 30.0f)];
    UIImage *backImage = [[UIImage imageNamed:@"back_button_normal.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12.0f, 0, 12.0f)];
    [backButton setBackgroundImage:backImage  forState:UIControlStateNormal];
    [backButton setTitle:@"Back" forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(popBack) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    self.navigationItem.leftBarButtonItem = backButtonItem;
}

-(void) popBack {
  [self.navigationController popViewControllerAnimated:YES];
}

Editar : Ne pas casser Geste de balayage ( Voici une source)

self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;

22voto

kolyuchiy Points 2987

L'image d'arrière-plan personnalisée n'apparaissant pas lors de la première poussée a été corrigée dans la version iOS 7 GM.

Pour cacher l'indicateur de dos standard, utilisez ce code :

if ([UINavigationBar instancesRespondToSelector:@selector(setBackIndicatorImage:)]) { // iOS 7
    [navigationBarAppearance setBackIndicatorImage:[UIImage imageNamed:@"transparent_1px"]];
    [navigationBarAppearance setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"transparent_1px"]];
}

13voto

Carl Lindberg Points 976

L'image d'arrière-plan personnalisée n'apparaissant pas au départ n'a pas été corrigée dans la version GM ou finale d'iOS7, pour autant que je sache. Je constate le même problème. Il semble qu'il s'agisse d'un bogue Apple ; la vue privée utilisée par Apple ne reçoit tout simplement pas d'appel setNeedsDisplay lorsqu'elle en a besoin lors de l'affichage initial. Si l'on fait quoi que ce soit qui provoque cet appel, cela devrait résoudre le problème -- comme appuyer dessus (ce qui change probablement l'état interne pour qu'elle appelle setNeedsDisplay sur elle-même), ou faire apparaître une modale (ce qui force probablement un réaffichage de toute la hiérarchie de la vue lors du prochain appel viewWillAppear :).

L'utilisation de leftBarItems à la place peut également fonctionner, mais cela peut causer beaucoup de problèmes de maintenance avec le code existant (certains écrans peuvent avoir leurs propres éléments de gauche, s'attendant à ce que lorsqu'ils sont remis à zéro, ils restaurent l'élément de gauche original, par exemple).

Comme indiqué, l'idéal serait de pouvoir passer à un aspect sans bordure sur iOS7, ce qui signifie que le bogue n'est pas vraiment apparent (puisqu'il n'y a pas d'image de fond). Cependant, dans certaines situations de transition iOS6/iOS7, cela peut s'avérer difficile (beaucoup d'écrans, et/ou la nécessité de supporter les anciennes versions d'iOS pendant un certain temps et trop difficile d'avoir deux looks implémentés, et cela ne rend pas bien sans bordure sans autres changements). Si c'est le cas, le patch suivant devrait fonctionner :

#import <objc/runtime.h>

@implementation UINavigationBar (BackButtonDisplayFix)

+ (void)load
{
    if ([UIDevice currentDevice].systemVersion.intValue >= 7)
    {
        /*
         * We first try to simply add an override version of didAddSubview: to the class.  If it
         * fails, that means that the class already has its own override implementation of the method
         * (which we are expecting in this case), so use a method-swap version instead.
         */
        Method didAddMethod = class_getInstanceMethod(self, @selector(_displaybugfixsuper_didAddSubview:));
        if (!class_addMethod(self, @selector(didAddSubview:),
                             method_getImplementation(didAddMethod),
                             method_getTypeEncoding(didAddMethod)))
        {
            Method existMethod = class_getInstanceMethod(self, @selector(didAddSubview:));
            Method replacement = class_getInstanceMethod(self, @selector(_displaybugfix_didAddSubview:));
            method_exchangeImplementations(existMethod, replacement);
        }
    }
}

- (void)_displaybugfixsuper_didAddSubview:(UIView *)subview
{
    [super didAddSubview:subview];
    [subview setNeedsDisplay];
}

- (void)_displaybugfix_didAddSubview:(UIView *)subview
{
    [self _displaybugfix_didAddSubview:subview]; // calls the existing method
    [subview setNeedsDisplay];
}

@end

Remarque : UINavigationBar dispose actuellement d'une surcharge de la méthode en question. Je m'attendrais donc à ce que le style method_exchangeImplementations soit utilisé. J'ai juste ajouté les autres éléments par sécurité, au cas où Apple modifierait son code. Il se peut que nous passions nous-mêmes au borderless, mais j'ai trouvé que cette approche fonctionnait comme une option (jusqu'à une mise à jour plus complète de l'interface utilisateur), au moins.

Note supplémentaire : Ce bogue semble être corrigé dans iOS 7.1. Ainsi, le correctif pourrait être conditionné pour n'installer les méthodes que si vous utilisez >= 7.0 et < 7.1.

6voto

Il existe une meilleure solution qui n'implique pas d'appliquer la méthode.

Vous devez ajouter la méthode UINavigationViewControllerDelegate quelque part dans votre application.

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
    [[navigationController.navigationBar subviews] makeObjectsPerformSelector:@selector(setNeedsDisplay)];
});

}

1voto

Chris Alan Points 880

Ajouter un bouton comme élément de navigation dans ios7 comme ci-dessous

 UIButton *btnAdd = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60, 30)];

        [btnAdd setContentMode:UIViewContentModeScaleAspectFit];

        [btnAdd setBackgroundImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal];

        [btnAdd addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

        UIBarButtonItem *btnAdd = [[UIBarButtonItem alloc] initWithCustomView:imView];

        self.navigationItem.rightBarButtonItem = btnAdd;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X