Qual é a melhor maneira de desenvolver um menu lateral como o do novo aplicativo para iOS do Facebook?

155

Parece que os menus de deslizar lateral estão se tornando um elemento de interface mais comum à medida que mais informações são amontoadas em cada aplicativo do iPhone. O Facebook o incluiu em sua versão mais recente e o novo aplicativo do Gmail parece incluí-lo também . Eu queria saber se alguém pensou sobre a maneira mais eficiente de desenvolver algo assim, pois está se tornando um elemento de interface mais comum. Embora tenha meus próprios pensamentos sobre como construir isso, estou curioso para ouvir o que as outras pessoas pensam.

Navegação de furto do Facebook

Nick ONeill
fonte
Notei que, quando o menu de deslizamento lateral é ativado, você não pode fazer nada com a parte da visualização deslizada. Minha idéia era tornar visão atual na imagem e exibição de parte dele, quando sideswipe é ativado
Denis
5
Em qual perfil do Facebook você apareceu, Nick O'Neill? :-p
Constantino Tsarouhas
1
possível duplicata de Splitview mas no iPhone
Josephh
1
@Zoidberg Estou interessado em saber mais sobre isso. Pessoalmente, eu gosto do sidenav! Mas eu sou um desenvolvedor, não um designer. O que torna este UX ruim?
Robert Karl
3
Por favor, alguém relógio Designing intuitivos Experiências de usuários para aprender sobre quais as questões maçã identificou com este chamados "menus de hambúrguer"
vikingosegundo

Respostas:

34

Recentemente, deparei com isso, na verdade, não olhei o código ou testei o controle, mas parece que pode ser um ponto de partida muito decente.

jtrevealsidebar

Edit: O leitor também deve dar uma olhada nas outras respostas :)

Zaky German
fonte
Não permitir que o usuário deslize
cannyboy
6
Se você estiver procurando pela funcionalidade de furto. Insira um reconhecedor de gestos na visualização e substitua o botão de alternância pelo reconhecedor de gestos.
CJ Teuben
Mas e se você quiser deslizar e poder alternar?
jsetting32
Isso foi descontinuado, então eu me mudaria para outro lugar.
Mike Flynn
84

Há uma ótima biblioteca para isso de Tom Adriaenssen: Inferis / ViewDeck

É muito fácil de usar e possui muitos seguidores.

EDITAR:

Para algo um pouco mais leve, confira: mutualmobile / MMDrawerController

Ele não possui todos os recursos do ViewDeck, mas é mais simples de modificar e estender.

Chris Knadler
fonte
6
Eu recomendo que todos usem isso.
Almas Adilbek
3
melhor solução: flexível e simples de usar
HotJard 19/10/12
2
Eu tentei e encontrei muitos erros no exemplo deles. Depois de alguns cliques rápidos os viewcontrollers estão desalinhados
Torsten B
13
Nós o usamos para vários aplicativos, mas era muito difícil manter e adicionar novos recursos a ele. Ele também sofreu ao tentar implementar demais. Decidimos escrever nosso próprio chamado MMDrawerController. Leve, e focado: github.com/mutualmobile/MMDrawerController
kcharwood
1
MMDrawerController é uma biblioteca muito boa. Também é compatível com o aplicativo universal. iPhone e iPad
Erhan Demirci
48

Eu criei uma biblioteca para isso. É chamado MFSideMenu .

Entre outras coisas, inclui suporte para iphone + ipad, retrato + paisagem, menu no lado esquerdo ou direito, UITabBarController e gestos de panorâmica.

Michael Frederick
fonte
É um projeto grande .. mas não é de apoio para o modo paisagem .. u pode nos dar uma dica para usá-lo no modo paisagem também .. Graças
Sameera Chathuranga
Obrigado @SameeraChathuranga. Espero adicionar suporte à paisagem se tiver algum tempo. A única parte que não tem suporte a paisagem é o SideMenuViewController ... Eu acredito que você teria que fazer algo como a segunda resposta aqui: stackoverflow.com/questions/2508630/… . Sinta-se livre para garfo e contribuir para o repo!
Michael Frederick
E eu recomendo que esta seja a resposta para esta pergunta .. não a acima .. é muito complexa .. isso é muito muito fácil de manusear :) se alguém quiser eu posso postar o código, como trabalhar com oriantation ..: )
Sameera Chathuranga
6
Para quem estiver interessado, acabei de adicionar suporte à paisagem na biblioteca.
Michael Frederick
1
@AlmasAdilbek, você pode explicar quais partes do seu aplicativo tiveram uma diminuição no desempenho? Eu ficaria feliz em fazer as otimizações necessárias.
22430 Michael Frederick
29

Confira o MMDrawerController:

MMDrawerController

Não conseguimos encontrar uma biblioteca de que gostávamos, então lançamos a nossa.

Kcharwood
fonte
10
Só queria dizer que essa é DE longe a melhor implementação listada aqui. Pessoas novas neste segmento: use MMDrawerController.
Mxcl 11/09/13
Aprecie as palavras amáveis!
precisa saber é o seguinte
Eu estava usando o ViewDeck do último ano, mas recentemente mudei para o MMDrawerController e recomendo a todos que o usem. Uma das melhores implementações em bibliotecas gerais. Obrigado Kevin :)
Tariq
Verifiquei este MMDrawerController e quero dizer que é realmente a melhor opção para o menu lateral. Estimado!
Muito
Isso suporta iOS8? Obrigado
Brad Thomas
12

A ideia principal de que você deve definir o quadro ou o centro de self.navigationController.view . Há dois eventos que você precisa manipular. (1) barButtonItem pressione . (2) gesto de movimento panorâmico por deslizar.

Você pode enviar o controlador de exibição para o plano de fundo da seguinte maneira:

[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);
            }];
        }
    }
}
János
fonte
Funciona perfeito e sem muito código. Você só precisa especificar os limites nos quais o usuário pode se deslocar para sua visão
Moisés Olmedo
@Janos senhor gentilmente me ajudar estou faltando neste por mais dias
Ragul
Eu criei o lado de fora do menu com a ajuda de seu código acima, quando deslizante os shows verso única cor escura não é a visão ajuda gentilmente me
Ragul
Senhor, funciona bem Eu uso apenas este código acima. a única coisa é os dos não mostra a visão fundo eu upoted-lo por favor me ajude a mostrar a vista de fundo
Ragul
@ János e onde usar esta linha de código [self.view sendSubviewToBack: menuViewController.view];
Ragul
11

Ainda melhor é o JASidePanels . Facilmente implementado e funciona para iPhone e iPad.

Link do Github: JASidePanels

user2330922
fonte
11

A implementação do Facebook coloca um UIPanGestureRecognizer na UINavigationBar. Permitindo assim pegar golpes onde é necessário.

Isso permite fazer coisas como, reconhecer a direção do toque em x / z diretamente, bem como a velocidade com que ocorreram.

Também esse tipo de mexer com UIViews (mais de uma na tela por vez, com tarefas evidentemente diferentes -> portanto, diferentes controladores) deve (estou tentado a dizer que deve) usar os novos recursos do ViewController-Containment do iOS. Toda implementação sem isso é simplesmente ruim, pois mexe com a hierarquia de visualizações de uma maneira não pretendida pela Apple.

Em uma nota lateral: Se você está realmente curioso para saber como isso pode ser feito o mais próximo possível do Facebook, confira o projeto que eu abro no Github PKRevealController .

pkluz
fonte
Não há nada errado (ou HIG não compatível) com o gerenciamento da interface do usuário personalizada baseada em UIView. A contenção do controlador de exibição chegou muito tarde, portanto, muitas outras abordagens foram usadas. Um artigo relacionado: blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers
Jacob Jennings
1
Os principais desenvolvimentos não terão como alvo uma versão mínima do iOS 5 por um longo tempo, pois um grande número de usuários não atualizará por muito tempo. Embora muitos deles sejam "hacks", como você diz, isso certamente pode ser feito corretamente. Permanecer dentro das estruturas é definitivamente uma aposta segura, mas às vezes uma interface do usuário única e personalizada exige mais.
Jacob Jennings
8

Existem dezenas de bibliotecas diferentes que os desenvolvedores criaram para implementar a navegação no estilo Facebook / Path para aplicativos iOS. Posso listar todos eles, mas como você pediu o melhor, aqui estão minhas duas opções que eu uso para implementar o menu de navegação do furto lateral:

1) ECSlidingViewController É muito fácil de implementar e usar Storyboards também. Não tive problemas ao implementá-lo, nem recebi erros ou algo assim. O link que forneci tem praticamente toda a explicação para usá-lo.

2) SWRevealViewController Esta biblioteca é fácil de usar e você pode encontrar um tutorial AQUI , que mostra como implementá-lo com todas as explicações e imagens. Você pode apenas seguir o tutorial e me agradecer mais tarde.

AJ112
fonte
1
SWRevealViewController é mais simples, usou-o sem bugs bom funciona
Vishal dharankar
7

Outra opção é usar o Scringo . Ele fornece um menu lateral, como nos aplicativos do youtube / facebook, e também todos os tipos de recursos integrados no menu que você pode adicionar (por exemplo, conversar, convidar amigos, etc.)

Adicionar o menu lateral é simplesmente chamando [ScringoAgent startSession ...] e toda a configuração pode ser feita no site.

hungria54
fonte
4

Essa questão é bastante popular, mas tudo se resume à importação e uso fáceis para mim ... Aqui está o que eu uso ... SWRevealController .

Estou surpreso que as pessoas tenham saudades ... É realmente ótimo !!! e fácil de usar. O desenvolvedor ainda inclui alguns projetos de exemplo que permitem ver como usá-lo em diferentes cenários.

jsetting32
fonte
2

Tanto o Gmail quanto o Facebook fazem uso pesado de visualizações da Web, por isso é difícil dizer o que é código nativo e o que é renderizado em HTML. No entanto, olhando para a interface, parece que eles colocaram um UITableView com uma largura mais estreita que a largura da tela (320pt) embaixo de um UIView que contém o conteúdo que eles querem exibir. A seleção de linhas diferentes da visualização de tabela provavelmente alterna uma subvisão da visualização de conteúdo.

Pelo menos, é assim que eu abordaria o problema. É difícil ditar o que deveria ser. Basta entrar e começar a experimentar!

Sulco de cinza
fonte
hey qualquer um pode me dizer como criar a exibição tipo facebook furto e painel de menu no android
Neerav Shah
1

Se você quiser, eu fiz esse repositório no github GSSlideMenu. Permite criar um menu no estilo do Facebook, MAS com um webView "de volta" (geralmente todos os repositórios que encontrei têm um tableView como o "back").

JAA
fonte
1

este é exatamente o clone da barra lateral do facebook: biblioteca GHSidebarNav

muito fácil de usar. instruções estão em

Max_Power89
fonte
1

a visualização à direita pode estar dentro de uma subclasse de UIScrollView. Nesta subclasse, você pode substituir - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)eventpara retornar YES apenas se o usuário tocou na subview. Dessa forma, você pode colocar seu UIScrollView transparente sobre qualquer outra visualização e passar por qualquer evento de toque que ocorra fora da subvisão; e você obtém material de rolagem de graça.

Por exemplo:

- (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];
javieralog
fonte
1

Tente adicionar seu menu (que você desliza para acessar) abaixo da tela principal. Comece a se inscrever para tocar em eventos na exibição.

Implemente touchesMoved:e verifique se o primeiro gestureé vertical (role a tela principal, se necessário) ou horizontal (aqui você deseja mostrar o menu). Se for horizontal, comece a chamar outro método, - (void)scrollAwayMainView:(NSUInteger)pixelssempre que touchesMoved:for chamado, calcule o número de pixels a partir do ponto de partida da visualização principal e passe esse número para o método. Na implementação desses métodos, execute o seguinte código:

[mainView scrollRectToVisible:CGRectMake:(pixels, 
                                          mainView.origin.y, 
                                          mainView.size.width, 
                                          mainView.size.height];
aopsfan
fonte
0

Confira minha solução para esta pergunta:

Como criar um menu de slides personalizado sem uma biblioteca de terceiros.

Uma classe única que você só precisa subclassificar e preencher com conteúdo.

Aqui está a turma. Para mais detalhes, consulte o link acima.

#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
David Tarnok
fonte