Cách tốt nhất để phát triển menu sidwipe như menu trong ứng dụng iOS mới của Facebook là gì?


155

Dường như các menu vuốt bên đang trở thành một yếu tố giao diện phổ biến hơn khi nhiều thông tin được nhồi nhét vào mỗi ứng dụng iPhone. Facebook đã đưa nó vào phiên bản mới nhất của họ và ứng dụng Gmail mới dường như cũng bao gồm nó . Tôi đã tự hỏi nếu có ai có suy nghĩ về cách phát triển hiệu quả nhất như thế này vì nó trở thành một yếu tố giao diện phổ biến hơn. Trong khi tôi có suy nghĩ riêng về cách xây dựng nó, tôi tò mò muốn nghe người khác nghĩ gì.

Điều hướng vuốt Facebook


Tôi đã nhận thấy rằng khi menu sidwipe được kích hoạt, bạn không thể làm bất cứ điều gì với phần bị xóa của chế độ xem. Ý tưởng của tôi là hiển thị chế độ xem hiện tại trong hình ảnh và phần hiển thị của nó, khi sidwipe được kích hoạt
Denis

5
Bạn đã xem lén hồ sơ Facebook của ai, Nick O'Neill? :-p
Constantino Tsarouhas

1
có thể trùng lặp với SplitView nhưng trên iPhone
JosephH

1
@Zoidberg Tôi rất muốn nghe thêm về điều này. Cá nhân, tôi thích sidenav! Nhưng tôi là một nhà phát triển, không phải là một nhà thiết kế. Điều gì làm cho UX này nghèo?
Robert Karl

3
Xin vui lòng bất cứ ai xem Thiết kế trải nghiệm người dùng trực quan để tìm hiểu về những vấn đề mà apple đã xác định với cái gọi là "menu hamburger" này
vikingosegundo 22/07/14

Câu trả lời:


34

Gần đây tôi đã tình cờ thấy điều này, không thực sự nhìn vào mã hoặc kiểm tra điều khiển, nhưng có vẻ như đó có thể là một điểm khởi đầu rất tốt.

jtrevealsidebar

Chỉnh sửa: Người đọc cũng nên xem các câu trả lời khác :)


Không cho phép người dùng trượt
cannyboy

6
Nếu bạn đang tìm kiếm chức năng vuốt. Chèn trình nhận dạng cử chỉ vào chế độ xem sau đó thay thế nút chuyển đổi bằng trình nhận dạng cử chỉ.
CJ Teuben

Nhưng nếu bạn muốn vuốt và có thể chuyển đổi thì sao?
jsett32

Điều này đã bị ngưng nên tôi sẽ chuyển đi nơi khác.
Mike Flynn

84

Có một thư viện tuyệt vời cho việc này của Tom Adriaenssen: Inferis / ViewDeck

Nó rất dễ sử dụng và có lượng người theo dõi khá lớn.

BIÊN TẬP:

Đối với một cái gì đó nhẹ hơn một chút, hãy xem: Mutmobile / MMDrawerControll

Nó không có tất cả các tính năng của ViewDeck nhưng đơn giản hơn để sửa đổi và mở rộng.


6
Tôi khuyên mọi người nên sử dụng cái này.
Almas Adilbek

3
Giải pháp tốt nhất: linh hoạt và đơn giản để sử dụng
HotJard

2
Tôi đã thử nó và tìm thấy rất nhiều lỗi trong ví dụ của họ. Sau khi nhấp chuột nhanh, bộ điều khiển khung nhìn bị căn chỉnh
Torsten B

13
Chúng tôi đã sử dụng nó cho một số ứng dụng, nhưng rất khó để duy trì và thêm các tính năng mới cho nó. Nó cũng đã phải chịu đựng khi cố gắng thực hiện quá nhiều. Chúng tôi đã quyết định viết MMDrawerControll của riêng mình. Trọng lượng nhẹ và tập trung: github.com/mutualmobile/MMDrawerControll
kcharwood

1
MMDrawerControll là thư viện rất tốt. Ngoài ra, nó còn hỗ trợ ứng dụng phổ quát. ứng dụng iphone và ipad
Erhan Demirci

48

Tôi đã tạo một thư viện cho việc này. Nó được gọi là MFSideMothy .

Trong số những thứ khác, nó bao gồm hỗ trợ cho iphone + ipad, dọc + ngang, menu ở bên trái hoặc bên phải, UITabBarContoder và cử chỉ xoay.


Đây là một dự án tuyệt vời .. nhưng nó không hỗ trợ cho chế độ phong cảnh .. Bạn có thể cho chúng tôi một gợi ý để sử dụng nó trong chế độ phong cảnh không .. Cảm ơn
Sameera Chathuranga

Cảm ơn @SameeraChathuranga. Tôi hy vọng sẽ thêm hỗ trợ cảnh quan nếu tôi có thời gian. Phần duy nhất không có hỗ trợ cảnh quan là SideMothyViewControll ... Tôi tin rằng bạn sẽ phải làm một cái gì đó giống như câu trả lời thứ 2 ở đây: stackoverflow.com/questions/2508630/ . Hãy rẽ nhánh và đóng góp cho repo!
Michael Frederick

Và tôi khuyên đây là câu trả lời cho câu hỏi này .. không phải câu hỏi trên .. nó quá phức tạp .. điều này rất dễ xử lý :) nếu ai đó muốn tôi có thể đăng mã, cách làm việc với oriantation ..: )
Sameera Chathuranga

6
Đối với bất cứ ai quan tâm, tôi chỉ cần thêm hỗ trợ cảnh quan vào thư viện.
Michael Frederick

1
@AlmasAdilbek, bạn có thể giải thích những phần nào trong ứng dụng của bạn bị giảm hiệu suất không? Tôi sẽ rất vui khi thực hiện bất kỳ tối ưu hóa cần thiết.
Michael Frederick

29

Kiểm tra MMDrawerControll:

MMDrawerControll

Chúng tôi không thể tìm thấy một thư viện mà chúng tôi thích, vì vậy chúng tôi chỉ tự cuộn.


10
Chỉ muốn nói rằng đây là BY FAR triển khai tốt nhất được liệt kê ở đây. Những người mới với chủ đề này: sử dụng MMDrawerControll.
mxcl

Đánh giá cao những lời tử tế!
gỗ thông

Tôi đã sử dụng ViewDeck từ một năm trước nhưng gần đây tôi đã chuyển sang MMDrawerControll và tôi khuyên mọi người nên sử dụng cái này. Một trong những triển khai tốt nhất trong các thư viện tổng thể. Cảm ơn Kevin :)
Tariq

Đã kiểm tra MMDrawerControll này và muốn nói rằng đó thực sự là lựa chọn tốt nhất cho menu bên. Đánh giá cao! Xin chân thành cảm ơn @Michael Frederick
Resty

Điều này có hỗ trợ iOS8 không? Cảm ơn
Brad Thomas

12

Các ý tưởng quan trọng mà bạn phải khung hoặc trung tâm bộ self.navigationController.view của . Có hai sự kiện mà bạn phải xử lý. (1) barButtonItem nhấn . (2) cử chỉ pan vì vuốt.

Bạn có thể gửi trình điều khiển xem đến nền như thế này:

[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);
            }];
        }
    }
}

Hoạt động hoàn hảo và không có quá nhiều mã. Bạn chỉ cần xác định các giới hạn mà người dùng có thể xoay để chế độ xem của bạn
Moisés Olmedo

@Janos thưa ngài, xin vui lòng giúp tôi thiếu điều này trong nhiều ngày nữa
Ragul

Tôi đã tạo menu bên ngoài với sự trợ giúp của mã trên của bạn, khi trượt mặt sau chỉ hiển thị màu tối chứ không phải chế độ xem vui lòng giúp tôi
Ragul

Thưa ông, nó hoạt động tốt. Tôi chỉ sử dụng mã trên. điều duy nhất là chế độ xem nền không hiển thị Tôi đã nâng cấp nó, vui lòng giúp tôi hiển thị chế độ xem nền
Ragul

@ János và nơi sử dụng dòng mã này [self.view sendSubviewToBack: menuViewControll.view];
Ragul


11

Việc triển khai của Facebook đặt một UIPanGestureRecognizer trên UINavlationBar. Do đó, cho phép bắt các giao dịch khi cần thiết.

Điều đó cho phép thực hiện những việc như, nhận biết hướng chạm trực tiếp trong x / z cũng như tốc độ chúng xảy ra.

Ngoài ra, việc sửa đổi như vậy với UIViews (nhiều hơn một lần trên màn hình với các nhiệm vụ rõ ràng khác nhau -> do đó, các bộ điều khiển khác nhau) nên (tôi muốn nói là phải) sử dụng các tính năng Ngăn chặn ViewContoder mới của iOS. Mọi việc thực hiện mà không có điều đó chỉ đơn giản là xấu vì nó tin tưởng vào hệ thống phân cấp xem theo cách không được Apple dự định.

Trên một sidenote: Nếu bạn thực sự tò mò về cách nó có thể được thực hiện gần với cách của Facebook nhất có thể, hãy xem dự án tôi mở có nguồn gốc trên Github PKRevealControll .


Không có gì sai (hoặc không tuân thủ HIG) với việc quản lý giao diện người dùng tùy chỉnh dựa trên UIView. Xem ngăn chặn bộ điều khiển đến quá muộn, vì vậy rất nhiều phương pháp khác đã được sử dụng. Một bài viết liên quan: blog.carbonfive.com/2011/03/09/abUSE-uiviewcontrollers
Jacob Jennings

1
Các phát triển chính sẽ không nhắm mục tiêu một phiên bản tối thiểu của iOS 5 trong một thời gian dài, vì một số lượng lớn người dùng sẽ không nâng cấp trong một thời gian rất dài. Trong khi nhiều người trong số họ là 'hack' như bạn nói, nó chắc chắn có thể được thực hiện chính xác. Ở trong các khung chắc chắn là một đặt cược an toàn, nhưng đôi khi một giao diện người dùng độc đáo và tùy chỉnh đòi hỏi nhiều hơn.
Jacob Jennings

8

Có hàng chục thư viện khác nhau mà các nhà phát triển đã tạo để thực hiện điều hướng kiểu Facebook / Path cho ứng dụng iOS. Tôi có thể liệt kê tất cả chúng nhưng như bạn đã yêu cầu cái tốt nhất, đây là hai lựa chọn của tôi mà tôi sử dụng để thực hiện menu điều hướng vuốt bên:

1) ECSlidingViewControll Nó cũng rất dễ thực hiện và sử dụng Storyboards. Tôi chưa có vấn đề gì khi thực hiện nó cũng như không nhận được bất kỳ lỗi nào hoặc bất cứ điều gì tương tự. Liên kết tôi cung cấp có khá nhiều lời giải thích để sử dụng nó.

2) SWRevealViewCont kiểm Thư viện này rất dễ sử dụng và bạn có thể tìm thấy một hướng dẫn TẠI ĐÂY , cho thấy cách thực hiện nó với tất cả các giải thích cùng với hình ảnh. Bạn chỉ có thể làm theo hướng dẫn và cảm ơn tôi sau.


1
SWRevealViewControll là đơn giản nhất, được sử dụng, không có lỗi nào hoạt động tốt
vishal dharankar

7

Một lựa chọn khác là sử dụng Scringo . Nó cung cấp cho bạn một menu phụ như trong ứng dụng youtube / facebook và tất cả các loại tính năng tích hợp trong menu mà bạn có thể chọn để thêm (ví dụ: trò chuyện, mời bạn bè, v.v.)

Thêm menu phụ chỉ đơn giản bằng cách gọi [ScringoAgent startSession ...] và tất cả cấu hình có thể được thực hiện trên trang web.



4

Câu hỏi này khá phổ biến nhưng tất cả đều dễ dàng nhập và sử dụng cho tôi ... Đây là những gì tôi sử dụng ... SWRevealControll .

Tôi ngạc nhiên khi mọi người nhớ nó ... Nó thực sự TUYỆT VỜI !!! và dễ sử dụng. Nhà phát triển thậm chí bao gồm một vài dự án ví dụ cho phép bạn xem cách sử dụng nó trong các tình huống khác nhau.



2

Cả Gmail và Facebook đều sử dụng rất nhiều lượt xem web, vì vậy thật khó để nói mã gốc là gì và HTML được hiển thị. Tuy nhiên, nhìn vào giao diện, có vẻ như họ đã đặt UITableView với chiều rộng hẹp hơn chiều rộng màn hình (320pt) bên dưới một UIView có chứa nội dung họ muốn hiển thị. Chọn các hàng xem bảng khác nhau có thể hoán đổi một khung nhìn phụ của chế độ xem nội dung.

Ít nhất, đó là cách tôi tiếp cận vấn đề. Thật khó để ra lệnh những gì nó nên được. Chỉ cần nhảy ngay vào và bắt đầu thử nghiệm!


này, bất kỳ ai cũng có thể cho tôi biết cách tạo chế độ xem kiểu vuốt facebook và bảng menu trong Android
Neerav Shah

1

Nếu bạn muốn tôi đã thực hiện repo này trên github GSSlideMothy Nó cho phép bạn tạo một menu kiểu Facebook NHƯNG với một webView "back" (nói chung tất cả các repos mà tôi tìm thấy đều có một viewView như chế độ xem "back").



1

Chế độ xem bên phải có thể nằm trong một lớp con của UIScrollView. Trong lớp con này, bạn có thể ghi đè - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)eventđể trả về CÓ chỉ khi người dùng chạm vào khung nhìn phụ. Bằng cách này, bạn có thể đặt UIScrollView trong suốt của mình lên bất kỳ chế độ xem nào khác và vượt qua mọi sự kiện chạm xảy ra bên ngoài khung nhìn phụ; và bạn có được công cụ cuộn miễn phí.

Ví dụ:

- (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);
}

hoặc là:

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

1

Hãy thử thêm menu của bạn (mà bạn vuốt để đến) bên dưới chế độ xem chính. Bắt đầu đăng ký để chạm vào các sự kiện trong chế độ xem.

Triển khai touchesMoved:và kiểm tra xem đầu tiên gesturelà dọc (cuộn chế độ xem chính, nếu cần) hoặc ngang (ở đây bạn muốn hiển thị menu). Nếu nó nằm ngang, hãy bắt đầu gọi một phương thức khác - (void)scrollAwayMainView:(NSUInteger)pixels, bất cứ khi nào touchesMoved:được gọi, tính toán số pixel ở điểm bắt đầu, chế độ xem chính sẽ là và chuyển số đó vào phương thức. Trong phương thức thực hiện đó, hãy chạy đoạn mã sau:

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

0

Kiểm tra giải pháp của tôi cho câu hỏi này:

Làm cách nào để tạo menu trượt tùy chỉnh mà không cần thư viện của bên thứ ba.?

Một lớp duy nhất mà bạn chỉ cần phân lớp và điền vào nội dung.

Đây là lớp học. Để biết thêm chi tiết, xem liên kết ở trên.

#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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.