web-dev-qa-db-fra.com

Quelle est la meilleure façon de développer un menu latéral comme celui de la nouvelle application iOS de Facebook?

Il semble que les menus de balayage latéral deviennent un élément d’interface plus courant à mesure que de plus en plus d’informations sont entassées dans chaque application iPhone. Facebook l'a incluse dans sa dernière version et la nouvelle application Gmail semble l'inclure également . Je me demandais si quelqu'un pensait au moyen le plus efficace de développer quelque chose comme cela, car il devient un élément d'interface plus commun. Alors que j'ai mes propres idées sur la façon de construire cela, je suis curieux d'entendre ce que les autres pensent.

Facebook swipe navigation

155
Nick ONeill

Je suis récemment tombé sur cette affaire, je n'ai pas réellement examiné le code ni testé le contrôle, mais il semble que ce soit un point de départ très décent.

jtrevealsidebar

Edit: le lecteur devrait également jeter un coup d'œil aux autres réponses :)

34
Zaky German

Il existe une excellente bibliothèque pour cela par Tom Adriaenssen: Inferis/ViewDeck

Il est très facile à utiliser et a un assez grand nombre de suiveurs.

EDIT:

Pour quelque chose d'un peu plus léger, consultez: mutualmobile/MMDrawerController

Il ne possède pas toutes les fonctionnalités de ViewDeck mais est plus simple à modifier et à étendre.

84
Chris Knadler

J'ai créé une bibliothèque pour cela. Cela s'appelle MFSideMen .

Entre autres choses, il inclut le support pour iphone + ipad, portrait + paysage, menu à gauche ou à droite, UITabBarController et mouvements de panoramique.

48
Michael Frederick

Découvrez MMDrawerController:

MMDrawerController

Nous ne pouvions pas trouver une bibliothèque qui nous plaisait, alors nous avons juste roulé la nôtre.

29
kcharwood

Le idée clé que vous devez définissez le cadre ou le centre de self.navigationController.view. Il y a deux événements que vous devez gérer. (1) presse barButtonItem. (2) geste panoramique à cause du balayage.

Vous pouvez envoyer le contrôleur de vue au fond comme ceci:

[self.view sendSubviewToBack:menuViewController.view];

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(buttonPressed:)];
    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [self.navigationController.view addGestureRecognizer:panGestureRecognizer];
    self.navigationItem.leftBarButtonItem = barButtonItem;
}

- (void)buttonPressed:(id)sender {

    CGRect destination = self.navigationController.view.frame;

    if (destination.Origin.x > 0) {
        destination.Origin.x = 0;
    } else {
        destination.Origin.x = 320;
    }

    [UIView animateWithDuration:0.25 animations:^{
        self.navigationController.view.frame = destination;
    }];
}

- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
    static CGPoint originalCenter;

    if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        originalCenter = recognizer.view.center;

    } else if (recognizer.state == UIGestureRecognizerStateChanged)
    {
        CGPoint translation = [recognizer translationInView:self.view];

        recognizer.view.center = CGPointMake(originalCenter.x + translation.x, originalCenter.y);
    }
    else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateFailed)
    {
        if (recognizer.view.frame.Origin.x < 160) {
            [UIView animateWithDuration:0.25 animations:^{
                recognizer.view.center = CGPointMake(384, 487.5);
            }];
        } else {
            [UIView animateWithDuration:0.25 animations:^{
                recognizer.view.center = CGPointMake(384 + 320, 487.5);
            }];
        }
    }
}
12
János

L'implémentation de Facebook place un UIPanGestureRecognizer sur le UINavigationBar. Permettant ainsi d’attraper des coups là où c’est nécessaire.

Cela permet, par exemple, de reconnaître directement la direction du toucher dans x/z ainsi que la vitesse à laquelle ils se sont produits.

De plus, ce genre de bricolage avec UIViews (plusieurs écrans à la fois avec des tâches évidemment différentes -> donc des contrôleurs différents) devrait (je suis tenté de le dire obligé) utiliser les nouvelles fonctionnalités de ViewController-Containment d'iOS. Toute implémentation sans cela est tout simplement mauvaise car elle modifie la hiérarchie des vues d’une manière qui n’est pas prévue par Apple.

Remarque: si vous êtes vraiment curieux de savoir comment cela peut être fait aussi proche que possible de Facebook, consultez le projet que j'ai ouvert et provenant de Github PKRevealController .

11
pkluz

Encore mieux est JASidePanels . Facilement implémenté et fonctionne pour iPhone et iPad.

Lien Github: JASidePanels

11
user2330922

Les développeurs ont créé des dizaines de bibliothèques pour implémenter la navigation de style Facebook/Path pour les applications iOS. Je peux les énumérer tous, mais comme vous avez demandé le meilleur, voici les deux choix que j’utilise pour implémenter le menu de navigation de balayage latéral:

1) ECSlidingViewController Il est très facile à implémenter et à utiliser également les Storyboards. Je n'ai eu aucun problème pour l'implémenter ni reçu d'erreurs ou quoi que ce soit du genre. Le lien que j'ai fourni contient à peu près toutes les explications nécessaires à son utilisation.

2) SWRevealViewController Cette bibliothèque est facile à utiliser et vous pouvez trouver un tutoriel ICI , qui montre comment l'implémenter avec tous les explication avec des images. Vous pouvez simplement suivre le tutoriel et me remercier plus tard.

8
AJ112

Une autre option consiste à utiliser Scringo . Il vous donne un menu latéral comme dans les applications youtube/facebook, ainsi que toutes sortes de fonctionnalités intégrées dans le menu que vous pouvez choisir d'ajouter (par exemple chatter, inviter des amis, etc.).

L'ajout du menu latéral se fait simplement en appelant [ScringoAgent startSession ...] et toute configuration peut être effectuée sur le site.

7
hungary54

Cette question est assez populaire mais tout se résume à une importation et une utilisation faciles pour moi ... Voici ce que j'utilise ... SWRevealController .

Je suis surpris que les gens me manquent ... C'est vraiment génial !!! et facile à utiliser. Le développeur inclut même quelques exemples de projets qui vous permettent de voir comment l’utiliser dans différents scénarios.

4
jsetting32

Référez-vous à ici, un très bon point de départ: glisser la navigation comme Facebook et chemin

4
ZTAN

Un excellent guide sur la manière de développer votre propre navigation par glissement dans Swift et Objective-C.).

Objective-C

Rapide

3
Victor Sigler

Gmail et Facebook utilisent tous deux énormément les vues Web. Il est donc difficile de déterminer le code natif et le rendu HTML. Cependant, en regardant l'interface, il semble qu'ils aient placé une UITableView avec une largeur plus étroite que la largeur de l'écran (320 pts) sous une vue UIV contenant le contenu qu'ils souhaitent afficher. La sélection de différentes lignes de la vue table remplace probablement une sous-vue de la vue contenu.

Au moins, c'est comme ça que j'approcherais le problème. Il est difficile de dicter ce que cela devrait être. Il suffit de sauter et de commencer à expérimenter!

2
Ash Furrow

Si vous voulez, j'ai fait ce dépôt sur github GSSlideMen Il vous permet de créer un menu de style Facebook MAIS avec une "WebView" "retour" (généralement, toutes les pensions que j'ai trouvées ont une tableView comme "retour". " vue).

1
JAA

la vue de droite pourrait se trouver dans une sous-classe de UIScrollView. Dans cette sous-classe, vous pouvez remplacer - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event pour renvoyer YES uniquement si l'utilisateur a touché la sous-vue. De cette façon, vous pouvez placer votre UIScrollView transparent sur toute autre vue et passer à travers tout événement tactile se déroulant en dehors de la sous-vue. et vous obtenez des choses de défilement gratuitement.

Par exemple:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    CGPoint location=[self convertPoint:point toView:subview];
    return (location.x > 0 && 
            location.x < subview.frame.size.width && 
            location.y > 0 && 
            location.y < subview.frame.size.height);
}

ou:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
    return [subview pointInside:
             [self convertPoint:point toView:subview] withEvent:event];
1
javieralog

c'est exactement le clone de la barre latérale de facebook: bibliothèque GHSidebarNav

très facile à utiliser. l'instruction est dans

1
Max_Power89

Essayez d’ajouter votre menu (que vous glissez pour vous y rendre) sous la vue principale. Commencez à vous abonner aux événements tactiles dans la vue.

Implémentez touchesMoved: Et vérifiez si le premier gesture est vertical (faites défiler la vue principale, si nécessaire) ou horizontal (dans ce cas, vous souhaitez afficher le menu). S'il est horizontal, commencez à appeler une autre méthode, - (void)scrollAwayMainView:(NSUInteger)pixels, à chaque appel de touchesMoved:, En calculant le nombre de pixels à partir du point de départ de la vue principale et en transmettant ce nombre à la méthode. . Dans cette implémentation de méthodes, exécutez le code suivant:

[mainView scrollRectToVisible:CGRectMake:(pixels, 
                                          mainView.Origin.y, 
                                          mainView.size.width, 
                                          mainView.size.height];
1
aopsfan

Découvrez ma solution pour cette question:

Comment créer un menu de diapositives personnalisé sans bibliothèque tierce .?

Une seule classe qu'il vous suffit de sous-classer et de renseigner avec du contenu.

Voici la classe. Pour plus de détails, voir le lien ci-dessus.

#import <UIKit/UIKit.h>

@interface IS_SlideMenu_View : UIView <UIGestureRecognizerDelegate>
{
    UIView* transparentBgView;
    BOOL hidden;
    int lastOrientation;
}

@property (strong, nonatomic) UIView *menuContainerV;

+ (id)sharedInstance;

- (BOOL)isShown;
- (void)hideSlideMenu;
- (void)showSlideMenu;

@end


#import "IS_SlideMenu_View.h"

@implementation IS_SlideMenu_View

+ (id)sharedInstance
{
    static id _sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[[self class] alloc] init];
    });

    return _sharedInstance;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    frame = [[[UIApplication sharedApplication] delegate] window].frame;
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];

        transparentBgView = [[UIView alloc] initWithFrame:frame];
        [transparentBgView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.6]];
        [transparentBgView setAlpha:0];
        transparentBgView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gestureRecognized:)];
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(gestureRecognized:)];
        [transparentBgView addGestureRecognizer:tap];
        [transparentBgView addGestureRecognizer:pan];

        [self addSubview:transparentBgView];

        frame.size.width = 280;
        self.menuContainerV = [[UIView alloc] initWithFrame:frame];
        CALayer *l = self.menuContainerV.layer;
        l.shadowColor = [UIColor blackColor].CGColor;
        l.shadowOffset = CGSizeMake(10, 0);
        l.shadowOpacity = 1;
        l.masksToBounds = NO;
        l.shadowRadius = 10;
        self.menuContainerV.autoresizingMask = UIViewAutoresizingFlexibleHeight;

        [self addSubview: self.menuContainerV];
        hidden = YES;
    }

    //----- SETUP DEVICE ORIENTATION CHANGE NOTIFICATION -----
    UIDevice *device = [UIDevice currentDevice];
    [device beginGeneratingDeviceOrientationNotifications];
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:device];

    lastOrientation = [[UIDevice currentDevice] orientation];

    return self;
}

//********** ORIENTATION CHANGED **********
- (void)orientationChanged:(NSNotification *)note
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];    
    if(orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight){
        NSLog(@"%ld",orientation);
        if(!hidden && lastOrientation != orientation){
            [self hideSlideMenu];
            hidden = YES;
            lastOrientation = orientation;
        }
    }
}

- (void)showSlideMenu {
    UIWindow* window = [[[UIApplication sharedApplication] delegate] window];
    self.frame = CGRectMake(0, 0, window.frame.size.width, window.frame.size.height);

    [self.menuContainerV setTransform:CGAffineTransformMakeTranslation(-window.frame.size.width, 0)];

    [window addSubview:self];
//    [[UIApplication sharedApplication] setStatusBarHidden:YES];

    [UIView animateWithDuration:0.5 animations:^{
        [self.menuContainerV setTransform:CGAffineTransformIdentity];
        [transparentBgView setAlpha:1];
    } completion:^(BOOL finished) {
        NSLog(@"Show complete!");
        hidden = NO;
    }];
}

- (void)gestureRecognized:(UIGestureRecognizer *)recognizer
{
    if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        [self hideSlideMenu];
    } else if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        static CGFloat startX;
        if (recognizer.state == UIGestureRecognizerStateBegan) {
            startX = [recognizer locationInView:self.window].x;
        } else
        if (recognizer.state == UIGestureRecognizerStateChanged) {
            CGFloat touchLocX = [recognizer locationInView:self.window].x;
            if (touchLocX < startX) {
                [self.menuContainerV setTransform:CGAffineTransformMakeTranslation(touchLocX - startX, 0)];
            }
        } else
        if (recognizer.state == UIGestureRecognizerStateEnded) {
            [self hideSlideMenu];
        }
    }
}

- (void)hideSlideMenu
{
    UIWindow* window = [[[UIApplication sharedApplication] delegate] window];
    window.backgroundColor = [UIColor clearColor];
    [UIView animateWithDuration:0.5 animations:^{
        [self.menuContainerV setTransform:CGAffineTransformMakeTranslation(-self.window.frame.size.width, 0)];
        [transparentBgView setAlpha:0];
    } completion:^(BOOL finished) {
        [self removeFromSuperview];
        [self.menuContainerV setTransform:CGAffineTransformIdentity];

//        [[UIApplication sharedApplication] setStatusBarHidden:NO];
        hidden = YES;
        NSLog(@"Hide complete!");
    }];
}

- (BOOL)isShown
{
    return !hidden;
}

@end
0
David Tarnok