Facebookの新しいiOSアプリにあるようなサイドワイプメニューを開発する最良の方法は何ですか?


155

より多くの情報が各iPhoneアプリに詰め込まれるにつれて、サイドスワイプメニューがより一般的なインターフェイス要素になっているようです。Facebookはそれを最新バージョンに含めており、新しいGmailアプリにも含まれているようです。このようなものを開発する最も効率的な方法は、より一般的なインターフェイス要素になりつつあるので、誰かが考えていたのではないかと思っていました。私はこれをどのように構築するかについて自分自身の考えを持っていますが、他の人々がどう思うか聞いてみたいです。

Facebookスワイプナビゲーション


横スワイプメニューがアクティブになっているとき、ビューの一部をスワイプアウトすると何もできないことに気づきました。私のアイデアは、サイドスワイプがアクティブになっているときに、現在のビューを画像にレンダリングしてその一部を表示することでした
Denis

5
Nick O'Neill、誰のFacebookプロフィールをのぞきましたか。:-p
コンスタンティーノツァロウハ11/11/22


1
@Zoidbergこれについてもっと知りたいです。個人的に、私はsidenavが好きです!しかし、私はデザイナーではなく開発者です。このUXが貧弱なのはなぜですか?
Robert Karl

3
Apple

回答:


34

私は最近これに遭遇しましたが、実際にコードを見たり、コントロールをテストしたりしていませんが、それは非常にまともな出発点であるように見えます。

jtrevealsidebar

編集:読者は他の回答も見てください:)


ユーザーがスライドすることを許可しません
cannyboy '09 / 09/27

6
スワイプ機能を探している場合。ジェスチャ認識機能をビューに挿入し、トグルボタンをジェスチャ認識機能に置き換えます。
CJ Teuben 2013年

しかし、スワイプしてトグルできるようにするにはどうすればよいでしょうか。
jsetting32 2013

これは廃止されたので、別の場所に移動します。
マイクフリン

84

Tom Adriaenssenによるこのための素晴らしいライブラリがあります:Inferis / ViewDeck

使い方はとても簡単で、かなりのフォロワーがいます。

編集:

もう少し軽量なものについては、以下をチェックしてください。mutualmobile/ MMDrawerController

ViewDeckのすべての機能を備えているわけではありませんが、変更と拡張が簡単です。


6
是非使ってみてください。
アルマスアディルベク2012

3
最適なソリューション:柔軟で使いやすい
HotJard

2
私はそれを試してみて、彼らの例にたくさんのバグを見つけました。いくつかの高速クリックの後、ビューコントローラーの位置がずれます
Torsten B

13
いくつかのアプリで使用しましたが、維持して新しい機能を追加するのは非常に困難でした。また、実装しすぎて苦しんでいます。独自のMMDrawerControllerを作成することにしました。軽量で集中型:github.com/mutualmobile/MMDrawerController
kcharwood

1
MMDrawerControllerは非常に優れたライブラリです。また、ユニバーサルアプリもサポートしています。iPhoneおよび
iPad

48

このためのライブラリを作成しました。これはMFSideMenuと呼ばれます

特に、iphone + ipad、portrait + landscape、左側または右側のメニュー、UITabBarController、およびパンジェスチャーのサポートが含まれます。


その偉大なプロジェクト..しかし、そのは、ランドスケープモードのためにサポートしていない.. uが..おかげで私たちにあまりにも風景モードでそれを使用するためのヒントを与えることができます
Sameera Chathuranga

@SameeraChathurangaに感謝します。時間があれば、ランドスケープのサポートを追加したいと思っています。:風景をサポートしていない部分のみがSideMenuViewControllerです...私はあなたがここに第二の答えのような何かをしなければならないと考えていstackoverflow.com/questions/2508630/...を。遠慮なくフォークしてレポに貢献してください!
マイケルフレデリック

そして、私はこれがこの質問の答えであることをお勧めします..上記のものではありません..それは非常に複雑です..これは非常に簡単に処理できます:)誰かが私がコードを投稿したい場合、どのようにoriantationで作業するか..: )
Sameera Chathuranga

6
興味のある方のために、ライブラリに横向きのサポートを追加しました。
マイケルフレデリック

1
@AlmasAdilbek、アプリのどの部分でパフォーマンスが低下したか説明できますか?必要に応じて最適化させていただきます。
マイケルフレデリック

29

MMDrawerControllerを確認してください。

MMDrawerController

気に入ったライブラリが見つからなかったので、自分でライブラリを作成しました。


10
これがBY FARであり、ここにリストされている最良の実装であると言いたかっただけです。このスレッドの初心者:MMDrawerControllerを使用します。
mxcl

優しい言葉に感謝!
kcharwood

私は過去1年間からViewDeckを使用していましたが、最近MMDrawerControllerに切り替えました。ライブラリ全体で最高の実装の1つ。ありがとうケビン:)
Tariq

このMMDrawerControllerをチェックして、サイドメニューの最良のオプションだと言いたいです。感謝!@Michael Frederickに感謝します
Resty

これはiOS8をサポートしていますか?ありがとう
ブラッドトーマス

12

キーアイデアあなたがしなければならないことself.navigationController.viewのフレームまたはセンターを設定。処理する必要がある2つのイベントがあります。(1)barButtonItem press。(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);
            }];
        }
    }
}

コードが多すぎず、完璧に動作します。あなただけのユーザーがあなたのビューので、パンすることができます制限を指定する必要があります
モイセスオルメド

@Janos先生、これ以上の日が足りないのを助けてくれます
Ragul

上記のコードを使用してサイドアウトメニューを作成しました。スライドアウトが暗い色のみを表示し、ビューが親切に助けてくれない場合
Ragul

うまくいきます。上記のコードのみを使用します。唯一のことは、背景ビューが私がそれを強調したことを示していないことです。背景ビューを表示するために私を助けてください
Ragul

@Jánosとこのコード行を使用する場所[self.view sendSubviewToBack:menuViewController.view];
Ragul

11

さらに良いのはJASidePanelsです。簡単に実装でき、iPhoneとiPadの両方で機能します。

Githubリンク:JASidePanels


11

Facebookの実装により、UIPanGestureRecognizerがUINavigationBarに配置されます。したがって、必要な場所でスワイプをキャッチできます。

これにより、x / zのタッチ方向を直接認識したり、発生した速度を認識したりすることができます。

また、UIViewをこのようにいじくり回す(明らかに異なるタスク->異なるコントローラーで一度に1つ以上画面に表示する)には、iOSの新しいViewController-Containment機能を使用する必要があります(私はそうしなければなりません)。Appleが意図していない方法でビュー階層をいじくり回すので、それなしのすべての実装は単に悪いです。

余談ですが、Facebookのできるだけ近くでそれを行う方法に本当に興味がある場合は、Github PKRevealControllerでソースを開いているプロジェクトをチェックしてください。


UIViewベースのカスタムUIの管理に問題はありません(またはHIGに準拠していません)。View Controllerの封じ込めが遅すぎたため、他の多くのアプローチが使用されてきました。関連記事:blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers
Jacob Jennings

1
多数のユーザーが非常に長期間アップグレードしないため、メジャーな開発はiOS 5の最小バージョンを長期間対象にしません。あなたが言うようにそれらの多くは「ハッキング」ですが、それは確かに正しく行うことができます。フレームワーク内に留まることは間違いなく安全な賭けですが、場合によっては、独自のカスタムUIがさらに必要になることがあります。
Jacob Jennings

8

iOSアプリのFacebook / Pathスタイルのナビゲーションを実装するために開発者が作成した数十の異なるライブラリがあります。私はそれらすべてをリストできますが、あなたが最高のものを求めたように、ここに私がサイドスワイプナビゲーションメニューを実装するために使用する私の2つの選択肢があります:

1)ECSlidingViewController ストーリーボードの実装と使用も非常に簡単です。私はそれを実装する問題を抱えていないし、エラーやそのようなものを受け取っていません。私が提供したリンクには、それを使用するためのほとんどすべての説明があります。

2)SWRevealViewController このライブラリは簡単に使用でき、画像とすべての説明とともにそれを実装する方法を示すチュートリアルがここにあります。チュートリアルに従うだけで、後で感謝します。


1
SWRevealViewControllerは最も単純なもので、バグが
なければ

7

別のオプションはScringoを使用することです。youtube / facebookアプリのようなサイドメニューを提供し、追加できるメニュー内のあらゆる種類の組み込み機能(たとえば、チャット、友達の招待など)を提供します

サイドメニューを追加するには、[ScringoAgent startSession ...]を呼び出すだけで、すべての構成をサイトで行うことができます。



4

この質問は非常に人気がありますが、すべて簡単にインポートして使用できました...これが私が使用するものです... SWRevealController

私は人々がそれを見逃していることに驚いています...それは本当に素晴らしいです!!! 使いやすいです。開発者には、さまざまなシナリオでの使用方法を確認できるいくつかのサンプルプロジェクトも含まれています。



2

GmailとFacebookはどちらもWebビューを多用しているため、ネイティブコードとレンダリングHTMLを区別するのは困難です。ただし、インターフェイスを見ると、表示したいコンテンツを含むUIViewの下に、画面幅(320pt)よりも狭い幅のUITableViewが配置されているようです。異なるテーブルビュー行を選択すると、おそらくコンテンツビューのサブビューがスワップアウトされます。

少なくとも、それが私が問題に取り組む方法です。それがどうあるべきかを指示するのは難しいです。すぐにジャンプして実験を開始してください!


AndroidでFacebookタイプのスワイプビューとメニューパネルを作成する方法を
誰かに

1

github GSSlideMenuでこのリポジトリ を作成したい場合は、Facebookスタイルのメニューを作成できます。



1

右側のビューは、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];

1

メインビューの下に(スワイプして表示される)メニューを追加してみてください。ビューのタッチイベントのサブスクライブを開始します。

を実装しtouchesMoved:、最初gestureが垂直(必要に応じてメインビューをスクロールする)か、水平(ここではメニューを表示する)かを確認します。水平の場合は- (void)scrollAwayMainView:(NSUInteger)pixels、別のメソッドの呼び出しを開始します。呼び出されるたびtouchesMoved:に、メインビューの開始点からのピクセル数を計算し、その数をメソッドに渡します。そのメソッドの実装で、次のコードを実行します。

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

0

この質問に対する私の解決策をチェックしてください:

サードパーティのライブラリなしでカスタムスライドメニューを作成する方法。

サブクラス化してコンテンツを入力するだけでよい単一のクラス。

こちらがクラスです。詳細については、上記のリンクを参照してください。

#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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.