iOS仿QQ側(cè)滑菜單

最近看到QQ上的側(cè)滑菜單特有意思,就自己試著去實(shí)現(xiàn)了一下栗菜,看上去效果相差不大。
最后的效果圖:



首先,需要自定義一個(gè)window
DBHWindow.h:

#import <UIKit/UIKit.h>

@interface DBHWindow : UIWindow

/**
 顯示左側(cè)視圖動(dòng)畫
 */
- (void)showLeftViewAnimation;

/**
 隱藏左側(cè)視圖動(dòng)畫
 */
- (void)hiddenLeftViewAnimation;

/**
 顯示左側(cè)視圖動(dòng)畫

 @param excursion 偏移寬度
 */
- (void)showLeftViewAnimationWithExcursion:(CGFloat)excursion;

@end

DBHWindow.m:

#import "DBHWindow.h"

#import "DBHRootViewController.h"

static NSString * const kDBHTableViewCellIdentifier = @"kDBHTableViewCellIdentifier";

@interface DBHWindow ()<UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIView *shadeView;

@end

@implementation DBHWindow

#pragma mark - Lifecycle
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setUI];
    }
    return self;
}

#pragma mark - UI
- (void)setUI {
    [self addSubview:self.tableView];
}

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kDBHTableViewCellIdentifier forIndexPath:indexPath];
    cell.textLabel.text = [NSString stringWithFormat:@"第%ld行", indexPath.row];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self hiddenLeftViewAnimation];
    DBHRootViewController *rootVC = (DBHRootViewController *)self.rootViewController.childViewControllers.firstObject;
    rootVC.selectedIndex = indexPath.row;
}

#pragma mark - Event Responds
/**
 點(diǎn)擊了右側(cè)半透明區(qū)域
 */
- (void)respondsToShadeView {
    [self hiddenLeftViewAnimation];
}
/**
 右側(cè)半透明區(qū)域的左滑手勢(shì)
 */
- (void)respondsToPanGR:(UIPanGestureRecognizer *)panGR {
    CGPoint position = [panGR translationInView:self.shadeView];

    // 手勢(shì)觸摸結(jié)束
    if (panGR.state == UIGestureRecognizerStateEnded) {
        if (- position.x > MAXEXCURSION * 0.5) {
            [self hiddenLeftViewAnimation];
        } else {
            [self showLeftViewAnimation];
        }

        return;
    }

    // 判斷是否滑出屏幕外
    if (position.x < - MAXEXCURSION || position.x > 0) {
        return;
    }

    [self showLeftViewAnimationWithExcursion:MAXEXCURSION + position.x];
}

#pragma mark - Public Methdos
/**
 顯示左側(cè)視圖動(dòng)畫
 */
- (void)showLeftViewAnimation {
    WEAKSELF
    [UIView animateWithDuration:0.25 animations:^{
        weakSelf.transform = CGAffineTransformTranslate(weakSelf.rootViewController.view.transform, MAXEXCURSION, 0);
        weakSelf.shadeView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
        [weakSelf addSubview:weakSelf.shadeView];
    }];
}
/**
 顯示左側(cè)視圖

 @param excursion 偏移大小
 */
- (void)showLeftViewAnimationWithExcursion:(CGFloat)excursion {
    self.transform = CGAffineTransformTranslate(self.rootViewController.view.transform, excursion, 0);
    self.shadeView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5 * (excursion / MAXEXCURSION)];
    if (!self.shadeView.superview) {
        [self addSubview:self.shadeView];
    }
}
/**
 隱藏左側(cè)視圖動(dòng)畫
 */
- (void)hiddenLeftViewAnimation {
    WEAKSELF
    [UIView animateWithDuration:0.25 animations:^{
        weakSelf.transform = CGAffineTransformIdentity;
        [weakSelf.shadeView removeFromSuperview];
    }];
}

#pragma mark - Private Methdos
/**
 重寫hitTest方法,點(diǎn)擊tableView才會(huì)響應(yīng)
 */
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];
    if (!view) {
        CGPoint newPoint = [self.tableView convertPoint:point fromView:self];
        if (CGRectContainsPoint(self.tableView.bounds, newPoint)) {
            view = self.tableView;
        }
    }
    return view;
}

#pragma mark - Getters And Setters
- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, -MAXEXCURSION, SCREENHEIGHT)];

        [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kDBHTableViewCellIdentifier];

        _tableView.dataSource = self;
        _tableView.delegate = self;
    }
    return _tableView;
}
- (UIView *)shadeView {
    if (!_shadeView) {
        _shadeView = [[UIView alloc] initWithFrame:self.bounds];
        _shadeView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];

        UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToShadeView)];
        UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToPanGR:)];
        [_shadeView addGestureRecognizer:tapGR];
        [_shadeView addGestureRecognizer:panGR];
    }
    return _shadeView;
}

其次,在主控制器中加上拖動(dòng)手勢(shì)椿争,使之看上去看炫
DBHRootViewController.h:

#import <UIKit/UIKit.h>

@interface DBHRootViewController : UIViewController

/**
 選中行數(shù)
 */
@property (nonatomic, assign) NSInteger selectedIndex;

@end

DBHRootViewController.m:

#import "DBHRootViewController.h"

#import "DBHWindow.h"

@interface DBHRootViewController ()

@property (nonatomic, assign) BOOL isBestLeft; // 是否為最左邊

@end

@implementation DBHRootViewController

#pragma mark - Lifecycle
- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"側(cè)滑Demo";
    self.view.backgroundColor = [UIColor whiteColor];

    [self setUI];
}

#pragma mark - UI
- (void)setUI {
    UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"showLeftView" style:UIBarButtonItemStylePlain target:self action:@selector(respondsToLeftBarButtonItem)];
    self.navigationItem.leftBarButtonItem = leftBarButtonItem;

    // 添加拖動(dòng)手勢(shì)
    UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToPanGR:)];
    [self.navigationController.view addGestureRecognizer:panGR];
}

#pragma mark - Event Responds
/**
 點(diǎn)擊showLeftView按鈕
 */
- (void)respondsToLeftBarButtonItem {
    DBHWindow *window = (DBHWindow *)[UIApplication sharedApplication].keyWindow;
    [window showLeftViewAnimation];
}
/**
 拖動(dòng)手勢(shì)調(diào)用的方法
 */
- (void)respondsToPanGR:(UIPanGestureRecognizer *)panGR {
    CGPoint clickPoint = [panGR locationInView:self.navigationController.view];
    CGPoint position = [panGR translationInView:self.navigationController.view];

    // 手勢(shì)觸摸開始
    if (panGR.state == UIGestureRecognizerStateBegan) {
        // 判斷手勢(shì)起始點(diǎn)是否在最左邊區(qū)域
        self.isBestLeft = clickPoint.x < LEFTMAXWIDTH;
    }

    DBHWindow *window = (DBHWindow *)[UIApplication sharedApplication].keyWindow;

    // 手勢(shì)觸摸結(jié)束
    if (panGR.state == UIGestureRecognizerStateEnded) {
        if (position.x > MAXEXCURSION * 0.5) {
            [window showLeftViewAnimation];
        } else {
            [window hiddenLeftViewAnimation];
        }

        return;
    }

    // 判斷是否滑出屏幕外或者拖動(dòng)手勢(shì)起始點(diǎn)是否在最左側(cè)區(qū)域
    if (position.x < 0 || position.x > MAXEXCURSION || !self.isBestLeft) {
        return;
    }

    [window showLeftViewAnimationWithExcursion:position.x];
}

#pragma mark - Getters And Setters
- (void)setSelectedIndex:(NSInteger)selectedIndex {
    _selectedIndex = selectedIndex;

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"點(diǎn)擊了第%ld行", _selectedIndex] message:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil]];
    [self presentViewController:alert animated:YES completion:nil];
}

@end

時(shí)間原因,加上只是想實(shí)現(xiàn)一個(gè)側(cè)滑的效果秘遏,左側(cè)的顯示視圖就隨意放了一個(gè)tableView丘薛,這里可以根據(jù)自己的需要換成其他視圖即可嘉竟。想看源碼的可以點(diǎn)擊最下面的地址下載邦危。
Demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舍扰,隨后出現(xiàn)的幾起案子倦蚪,更是在濱河造成了極大的恐慌,老刑警劉巖边苹,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陵且,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡个束,警方通過查閱死者的電腦和手機(jī)慕购,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茬底,“玉大人沪悲,你說我怎么就攤上這事≮灞恚” “怎么了殿如?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長最爬。 經(jīng)常有香客問我涉馁,道長,這世上最難降的妖魔是什么爱致? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任烤送,我火速辦了婚禮,結(jié)果婚禮上糠悯,老公的妹妹穿的比我還像新娘胯努。我一直安慰自己,他們只是感情好逢防,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布叶沛。 她就那樣靜靜地躺著,像睡著了一般忘朝。 火紅的嫁衣襯著肌膚如雪灰署。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音溉箕,去河邊找鬼晦墙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛肴茄,可吹牛的內(nèi)容都是我干的晌畅。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼寡痰,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼抗楔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拦坠,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤连躏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后贞滨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體入热,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年晓铆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勺良。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骄噪,死狀恐怖尚困,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腰池,我是刑警寧澤尾组,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站示弓,受9級(jí)特大地震影響讳侨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奏属,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一跨跨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囱皿,春花似錦勇婴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至齿兔,卻和暖如春橱脸,著一層夾襖步出監(jiān)牢的瞬間础米,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國打工添诉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屁桑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓栏赴,卻偏偏與公主長得像蘑斧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子须眷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容