开发Facebook的新iOS应用程序中的侧滑菜单的最佳方式是什么?

看起来,侧滑菜单正在成为一个更常见的界面元素,因为更多的信息被塞进每个iPhone应用程序。 Facebook已经将其包含在他们的最新版本中, 新的Gmail应用程序似乎也包含了它 。 我想知道是不是有人有这样的想法,因为它正在成为一个更常见的界面元素。 虽然我有自己的想法如何build立这个,我很好奇听到别人的想法。

Facebook刷卡导航

我最近碰到这个,实际上并没有看代码或testing控制,但看起来可能是一个非常体面的起点。

jtrevealsidebar

编辑:读者也应该看看其他的答案:)

Tom Adriaenssen有一个很棒的图书馆: Inferis / ViewDeck

它使用起来非常简单,并且有相当大的跟随。

编辑:

对于更轻量级的东西,请查看: mutualmobile / MMDrawerController

它没有ViewDeck的所有function,但修改和扩展更简单。

我为此创build了一个库。 它被称为MFSideMenu 。

其中包括支持iPhone + iPad,纵向+横向,左侧或右侧菜单,UITabBarController和平移手势。

检查出MMDrawerController:

MMDrawerController

我们找不到一个我们喜欢的图书馆,所以我们只是推出了自己的图书馆。

关键的想法 ,你必须设置self.navigationController.view的框架或中心 。 有两个事件 ,你必须处理。 (1) barButtonItem按 。 (2)因滑动而出现的平移手势

你可以发送视图控制器到这样的背景:

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

更好的是JASidePanels 。 轻松实现,适用于iPhone和iPad。

Github链接: JASidePanels

Facebook的实现将一个UIPanGestureRecognizer放置在UINavigationBar上。 从而可以在需要的地方捕捉到滑动。

这允许做一些事情,例如直接识别x / z中的触摸方向以及它们发生的速度。

同样,这种修补与UIViews(在屏幕上一次显然不同的任务 – >因此不同的控制器)应该(我很想说)必须使用iOS新的ViewController-Containmentfunction。 没有这个的每一个实现都是非常糟糕的,因为它与苹果公司不打算的视图层次结构一样。

在旁注:如果你真的好奇如何尽可能接近Facebook的方式,请检查我在Github PKRevealController上开源的项目。

开发人员已经创build了几十个不同的库来实现iOS应用的Facebook / Path风格导航。 我可以列出所有这些,但是,因为您已经要求最好的一个,这里是我用来实现侧滑动导航菜单的两个select:

1) ECSlidingViewController它也很容易实现和使用故事板。 我没有执行任何问题,也没有收到任何错误或类似的东西。 我提供的链接有几乎所有的解释,以便使用它。

2) SWRevealViewController这个库很容易使用,你可以在这里find一个教程,它展示了如何使用所有的解释和图像来实现它。 您可以按照教程,稍后再感谢我。

另一个select是使用Scringo 。 它提供了youtube / facebook应用程序中的侧边菜单,还有菜单中的所有内置function,您可以select添加(例如聊天,邀请朋友等)

添加侧面菜单只需调用[ScringoAgent startSession …],所有的configuration都可以在网站上完成。

请参考这里,一个非常好的起点: 滑出如Facebook和path的导航

这个问题是相当stream行的,但一切都归结为简单的导入和使用我…这是我使用… SWRevealController 。

我很惊讶的人错过了它真的很棒! 并且易于使用。 开发人员甚至包括一些示例项目,可以让你看到如何在不同的场景中使用它。

Gmail和Facebook都大量使用networking浏览,所以很难说什么是本地代码和什么是HTML。 然而,看着界面,看起来他们已经放置了一个UITableView的宽度比UIView下面的屏幕宽度窄(320pt),它包含了他们想要显示的内容。 select不同的tableview行可能会掉掉内容视图的子视图。

至less,这就是我如何处理这个问题。 很难指定它应该是什么。 只需跳进来开始试验!

如果你想我在github上做了这个回购GSSlideMenu它允许你创build一个Facebook式的菜单,但有一个“后退”的webView(通常我发现有一个tableView作为“后退”视图)。

这正是Facebook侧边栏的副本: GHSidebarNav库

非常容易使用。 指令在

右边的视图可以在UIScrollView的子类中。 在这个子类中,你可以覆盖- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event只有在用户触及子视图时才返回YES。 这样,您可以将透明UIScrollView放置在任何其他视图上,并通过在子视图外部发生的任何触摸事件。 你可以免费获得滚动的东西。

例如:

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

要么:

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

尝试添加你的菜单(你滑动到)在主视图下。 开始订阅触摸视图中的事件。

实现touchesMoved:并检查第一个gesture是垂直的(如果需要的话,滚动主视图)或水平的(在这里你要显示菜单)。 如果是水平的,则开始调用另一个方法: - (void)scrollAwayMainView:(NSUInteger)pixels ,每当touchesMoved:被调用时,计算远离主视图的起始点的像素数量,并将该数字传递给方法。 在该方法实现中,运行以下代码:

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

看看我的解决scheme这个问题:

如何创build没有第三方库的自定义幻灯片菜单?

一个单一的类,你只需要inheritance和内容填充。

这是class级。 有关更多详细信息,请参阅上面的链接。

 #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