iOS開發(fā)之路--仿網(wǎng)易抽屜效果
最終效果圖:

MainStoryBoard示意圖:

BeyondViewController.h
// // BeyondViewController.h // 19_抽屜效果_仿網(wǎng)易 // // Created by beyond on 14-8-1. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import <UIKit/UIKit.h> #import "LeftTableViewControllerDelegate.h" @interface BeyondViewController : UIViewController // 左半邊 (顯示 的是欄目列表 ) @property (weak, nonatomic) IBOutlet UIView *leftView; // 右半邊 (顯示 的是個(gè)人信息設(shè)置視圖) @property (weak, nonatomic) IBOutlet UIView *rightView; // 最上面,最大的全屏的是主視圖 @property (weak, nonatomic) IBOutlet UIView *mainView; // 上面標(biāo)題狀態(tài)欄視圖中的標(biāo)題按鈕 (網(wǎng)易的Logo圖片和欄目的名稱 水平排列) @property (weak, nonatomic) IBOutlet UIButton *titleBtn; // mainView的下半部分 是 正文的view,顯示子欄目的view @property (weak, nonatomic) IBOutlet UIView *contentView; // pan 拽 手勢(shì)處理 - (IBAction)panGesture:(UIPanGestureRecognizer *)sender; // mainView的上半部分 標(biāo)題狀態(tài)欄視圖中的左,右按鈕 - (IBAction)btnClick:(UIButton *)sender; @end
BeyondViewController.m
//
// BeyondViewController.m
// 19_抽屜效果_仿網(wǎng)易
//
// Created by beyond on 14-8-1.
// Copyright (c) 2014年 com.beyond. All rights reserved.
//
#import "BeyondViewController.h"
#import "LeftTableViewController.h"
#import "RightViewController.h"
#import "Column.h"
#import <QuartzCore/QuartzCore.h>
// 手勢(shì)結(jié)束時(shí)的x
#define kEndX frame.origin.x
// 左view的寬度
#define kLeftWidth _leftView.frame.size.width
// 右view的寬度
#define kRightWidth _rightView.frame.size.width
// 對(duì)協(xié)議進(jìn)行提前聲明
@protocol LeftTableViewControllerDelegate ;
@interface BeyondViewController ()<LeftTableViewControllerDelegate>
{
// 手指按下的時(shí)候,記住,mainView的起始x
CGFloat _startX;
// 成員變量,記住左邊控制器的實(shí)例
LeftTableViewController *_leftVC;
// 成員變量,記住右邊控制器的實(shí)例
RightViewController *_rightVC;
// 字典 ,記住所有實(shí)例化了 欄目的子控制器,避免每次都重新創(chuàng)建
NSMutableDictionary *_columnViewControllers;
}
@end
@implementation BeyondViewController
// 隱藏狀態(tài)欄
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_titleBtn.backgroundColor = [UIColor clearColor];
// 0 字典 ,記住所有實(shí)例化了 欄目的子控制器,避免每次都重新創(chuàng)建
_columnViewControllers = [NSMutableDictionary dictionary];
// 0,設(shè)置導(dǎo)航條bar的背景 為網(wǎng) 易 紅
//[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"bg.png"] forBarMetrics:UIBarMetricsDefault];
// 狀態(tài)條顏色 改成默認(rèn)的樣式
//[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
// 1,添加左邊控制器的view到左邊的view里面
_leftVC = [[LeftTableViewController alloc]init];
// 關(guān)鍵代碼 為了拿到左邊控制器的某一行被點(diǎn)擊時(shí)候,對(duì)應(yīng)的欄目數(shù)據(jù)模型對(duì)象,主控制器成為了左邊控制器的代理,遵守了它定好的協(xié)議,實(shí)現(xiàn)了協(xié)議中的方法,從而拿到左邊控制器被點(diǎn)擊行號(hào)對(duì)應(yīng)的數(shù)據(jù)模型對(duì)象
_leftVC.delegate = self;
_leftVC.view.frame = self.leftView.bounds;
[self.leftView addSubview:_leftVC.view];
// 2,同理,添加右邊控制器的view到右邊的view里面
_rightVC = [[RightViewController alloc]init];
_rightVC.view.frame = self.rightView.bounds;
[self.rightView addSubview:_rightVC.view];
// 3,第一次加載時(shí)候,就就應(yīng)該顯示新聞 子欄目的控制器到導(dǎo)航控制器,再將導(dǎo)航控制器的view添加到 mainView里面
[self firstLoading];
}
// 自定義方法,第一次加載時(shí)候,就就應(yīng)該顯示新聞 子欄目的控制器到導(dǎo)航控制器,再將導(dǎo)航控制器的view添加到 mainView里面
- (void)firstLoading
{
Column * column = [Column columnNamed:@"新聞" imgName:@"news.png" className:@"NewsViewController"];
// 僅需手動(dòng)調(diào)用一個(gè) LeftViewController的代理 方法,leftTableViewRowClicked,傳遞一個(gè)新聞 子欄目即可
[self leftTableViewRowClicked:column];
}
// pan 拽 手勢(shì)處理
- (IBAction)panGesture:(UIPanGestureRecognizer *)sender
{
// 如果是剛按下的狀態(tài),則記住,mainView的起始x
if (UIGestureRecognizerStateBegan == sender.state) {
_startX = self.mainView.frame.origin.x;
}
// 平移拖動(dòng)的距離
CGPoint delta = [sender translationInView:_mainView];
CGRect frame = self.mainView.frame;
// 計(jì)算新的x值,并做健壯性判斷
kEndX = _startX + delta.x;
// 1,限制最大拖動(dòng)范圍
if (kEndX >= kLeftWidth) {
kEndX = kLeftWidth;
}
if (kEndX <= - kRightWidth) {
kEndX = - kRightWidth;
}
// 2,由于 左view和右view在重疊,所以要隱藏其中的一個(gè)
if (kEndX > 0) {
// NSLog(@"--調(diào)用頻率相當(dāng)高--");
_rightView.hidden = YES;
_leftView.hidden = NO;
} else {
_rightView.hidden = NO;
_leftView.hidden = YES;
}
if (UIGestureRecognizerStateEnded == sender.state) {
// 手勢(shì)結(jié)束的時(shí)候,需進(jìn)行robust判斷
// 2,分析end松手時(shí)候,的位置x,決定展開到什么程度
/*
// 2.1 如果只向右拖了一點(diǎn)點(diǎn),小于 1/2 的左view的寬度,則歸0
if (kEndX < 0.5*kLeftWidth && kEndX >= 0) {
kEndX = 0;
}else if (kEndX >= 0.5*kLeftWidth && kEndX <= kLeftWidth) {
// 2.2 如果向右拖一大半了,大于 1/2 的左view的寬度,雖然還沒(méi)到位,也可以認(rèn)為是到位了
kEndX = kLeftWidth;
}else if (kEndX > - 0.5*kRightWidth && kEndX <= 0) {
// 2.3 如果只向左拖了一點(diǎn)點(diǎn),小于 1/2 的右view的寬度,則歸0
kEndX = 0;
}else if (kEndX <= - 0.5*kRightWidth) {
// 2.4 如果向左拖一大半了,大于 1/2 的右view的寬度,雖然還沒(méi)到位,也可以認(rèn)為是到位了
kEndX = - kRightWidth;
}
*/
// 第2種判斷方式
// 起始為0,delta.x大于0 代表向右滑動(dòng)
if (_startX == 0 && delta.x >0) {
kEndX = kLeftWidth;
}else if (_startX == 0 && delta.x < 0){
// 起始為0,delta.x小于0 代表向左滑動(dòng)
kEndX = - kRightWidth;
}else if (_startX == kLeftWidth && delta.x < 0){
// 起始為kLeftWidth,delta.x小于0 代表向左滑動(dòng)
kEndX =0;
}else if (_startX == - kRightWidth && delta.x > 0){
// 起始為- kRightWidth,delta.x大于0 代表向右滑動(dòng)
kEndX = 0;
}
}
// 最后,才設(shè)置mainView的新的frame
[UIView animateWithDuration:0.2 animations:^{
self.mainView.frame=frame;
}];
// 最后,為mainView所在的圖層 添加陰影效果
[self addShadowFormainViewWithEndX:kEndX];
}
// 自定義方法,為mainView所在的圖層 添加陰影效果 (調(diào)用頻率相當(dāng)高)
- (void)addShadowFormainViewWithEndX:(CGFloat)endX
{
// 1,點(diǎn)擊工程,加號(hào),導(dǎo)入第3方框架 #import <QuartzCore/QuartzCore.h>
// 2,拿到mainView所在的圖層,設(shè)置陰影 參數(shù)
// NSLog(@"調(diào)用頻率很高---");
_mainView.layer.shadowColor = [UIColor blackColor].CGColor;
_mainView.layer.shadowOpacity = 0.5;
if (endX >= 0) {
_mainView.layer.shadowOffset = CGSizeMake(-5, 0);
} else {
_mainView.layer.shadowOffset = CGSizeMake(5, 0);
}
}
// 單擊按鈕,也一樣可以展開 左右側(cè)邊欄
- (IBAction)btnClick:(UIButton *)sender
{
// 定義一個(gè)臨時(shí)變量
CGFloat startX = _mainView.frame.origin.x;
// 先為mainView所在的圖層 添加陰影效果
[self addShadowFormainViewWithEndX:sender.tag == 1?1:-1];
// 定義一個(gè)臨時(shí)變量
CGFloat tempEndX = 0;
// 左邊的按鈕被單擊
if (1 == sender.tag) {
// 隱藏右半邊
_leftView.hidden = NO;
_rightView.hidden = YES;
if (startX == 0) {
tempEndX = kLeftWidth;
}else if (startX == kLeftWidth){
tempEndX = 0;
}
} else {
// 單擊右邊按鈕, 隱藏左半邊
_leftView.hidden = YES;
_rightView.hidden = NO;
if (startX == 0) {
tempEndX = - kRightWidth;
}else if (startX == - kRightWidth){
tempEndX = 0;
}
}
// 最后才設(shè)置mainView的x,調(diào)用抽取出來(lái)的公共代碼,設(shè)置mainView的x,參數(shù)是endX
[self setmainViewX:tempEndX];
}
// 抽取出來(lái)的公共代碼,設(shè)置mainView的x,參數(shù)是endX
- (void)setmainViewX:(CGFloat)endX
{
CGRect frame = self.mainView.frame;
frame.origin.x = endX;
[UIView animateWithDuration:0.2 animations:^{
self.mainView.frame=frame;
}];
}
// 最關(guān)鍵的方法,左邊控制器的代理 方法,當(dāng)前左邊控制器中的某一行被點(diǎn)擊的時(shí)候 會(huì)調(diào)用
- (void)leftTableViewRowClicked:(id)columnSelected
{
Column *column = (Column *)columnSelected;
// 1,關(guān)閉左邊的控制=======================
// 調(diào)用抽取出來(lái)的公共代碼,設(shè)置mainView的x,參數(shù)是endX
[self setmainViewX:0];
// 2,更改標(biāo)題按鈕上面的文字
_titleBtn.titleLabel.text = column.columnName;
// 根據(jù)欄目數(shù)據(jù)模型中的類名,實(shí)例化對(duì)應(yīng)欄目的控制器,并且將其設(shè)置為導(dǎo)航控制器的根控制器,最后將導(dǎo)航控制器的view添加到mainView中,目的是方便設(shè)置導(dǎo)航條,以及,各控制器的跳轉(zhuǎn)
// 2,從緩存字典中取,如果子控制器字典有曾經(jīng)創(chuàng)建過(guò)的子控制器,直接取出來(lái)用
UIViewController *columnVC = _columnViewControllers[column.columnClassName];
// 如果子控制器字典中沒(méi)有保存過(guò)該欄目的控制器,才要?jiǎng)?chuàng)建子控制器
if (columnVC == nil) {
Class c = NSClassFromString(column.columnClassName);
columnVC = [[c alloc]init];
// 并且一定要將其放到 子控制器字典里面,存起來(lái)
[_columnViewControllers setObject:columnVC forKey:column.columnClassName];
}
// 4,移除contentView中的正在顯示的舊的子view
if (_contentView.subviews.count > 0) {
UIView *oldView = [_contentView subviews][0];
[oldView removeFromSuperview];
}
// 5,最后將子控制器的view添加到contentView中,顯示
columnVC.view.frame = _contentView.bounds;
[self.contentView addSubview:columnVC.view];
NSLog(@"%@",self.contentView);
// 在添加到mainView之前 ,先得到mainView導(dǎo)航控制器的子控制器,并將其移除(如果有的話),然后才將新的欄目對(duì)應(yīng)的子控制器添加到導(dǎo)航控制器容器中,注意,這兒可以用字典 記住 所有的已經(jīng)實(shí)例化出來(lái) 的欄目子控制器,這樣就避免每次都alloc創(chuàng)建新的欄目子控制器,而是只需要根據(jù)類名,從字典取出上一次實(shí)例化了的同一欄目的子控制器即可
}
@end
欄目數(shù)據(jù)模型Column.h
// // Column.h // 19_抽屜效果_仿網(wǎng)易 // // Created by beyond on 14-8-1. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import <Foundation/Foundation.h> // 數(shù)據(jù)模型 代表一個(gè)欄目 @interface Column : NSObject // 欄目名稱 @property (nonatomic,copy)NSString *columnName; // 欄目圖片名稱 @property (nonatomic,copy)NSString *columnImgName; // 欄目對(duì)應(yīng)的控制器的類名 @property (nonatomic,copy)NSString *columnClassName; // UI控件用weak,字符串用copy,其他對(duì)象用strong // 提供一個(gè)類方法,即構(gòu)造函數(shù),返回封裝好數(shù)據(jù)的對(duì)象(返回id亦可) + (Column *)columnNamed:(NSString *)columnName imgName:(NSString*)columnImgName className:(NSString *)columnClassName; @end
欄目數(shù)據(jù)模型Column.m
//
// Column.m
// 19_抽屜效果_仿網(wǎng)易
//
// Created by beyond on 14-8-1.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 數(shù)據(jù)模型 代表一條欄目
#import "Column.h"
@implementation Column
// 返回一個(gè)包含了 欄目對(duì)應(yīng)控制器名字的 對(duì)象實(shí)例
+ (Column *)columnNamed:(NSString *)columnName imgName:(NSString *)columnImgName className:(NSString *)columnClassName
{
// 為了兼容子類 使用self
Column *column = [[self alloc]init];
column.columnName = columnName;
column.columnImgName = columnImgName;
column.columnClassName = columnClassName;
return column;
}
@end
左邊控制器定義好的協(xié)議LeftTableViewControllerDelegate.h
// // LeftTableViewControllerDelegate.h // 19_抽屜效果_仿網(wǎng)易 // // Created by beyond on 14-8-1. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import <Foundation/Foundation.h> #import "Column.h" // 左邊控制器 定義的代理/協(xié)議 它通過(guò)調(diào)用自己的成員屬性(即代理)的該方法,將數(shù)據(jù)傳遞出去(給它的代理去使用) (其實(shí) 是主控制器想要數(shù)據(jù),所以主控制器在實(shí)例化左邊控制器的時(shí)候,要設(shè)置左邊控制器對(duì)應(yīng)的代理 為 主控制器 自身) @protocol LeftTableViewControllerDelegate <NSObject> - (void)leftTableViewRowClicked:(Column *)columnSelected; @end
LeftTableViewController.h
// // LeftTableViewController.h // 19_抽屜效果_仿網(wǎng)易 // // Created by beyond on 14-8-1. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import <UIKit/UIKit.h> // 對(duì)協(xié)議進(jìn)行提前聲明 @protocol LeftTableViewControllerDelegate; @interface LeftTableViewController : UITableViewController // 代理 用weak,防止循環(huán)問(wèn)題,可以是任意類型,但必須遵守協(xié)議 @property (nonatomic,weak) id<LeftTableViewControllerDelegate> delegate; @end
LeftTableViewController.m
//
// LeftTableViewController.m
// 19_抽屜效果_仿網(wǎng)易
//
// Created by beyond on 14-8-1.
// Copyright (c) 2014年 com.beyond. All rights reserved.
//
#import "LeftTableViewController.h"
#import "Column.h"
#import "LeftTableViewControllerDelegate.h"
@interface LeftTableViewController ()
{
// 欄目數(shù)組,保存的是左邊欄目列表中的所有欄目對(duì)象
NSArray *_arr;
}
@end
@implementation LeftTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 新聞 欄目
Column *newsColumn = [Column columnNamed:@"新聞" imgName:@"news.png" className:@"NewsViewController"];
// 圖片 欄目
Column *picColumn = [Column columnNamed:@"圖片" imgName:@"pic.png" className:@"PicViewController"];
// 圖片 欄目
Column *commentColumn = [Column columnNamed:@"跟帖" imgName:@"comment.png" className:@"CommentViewController"];
// 以后要添加欄目,只要改這里就可以了
// 將欄目對(duì)象,一次性全添加到不可變數(shù)組中
_arr = @[newsColumn,picColumn,commentColumn];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _arr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"leftVC";
// 下面這個(gè)dequeue只能用于storyboard或xib中
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
//
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
// 設(shè)置獨(dú)一無(wú)二的數(shù)據(jù)
Column *column = _arr[indexPath.row];
cell.textLabel.text = column.columnName;
cell.imageView.image = [UIImage imageNamed:column.columnImgName];
return cell;
}
// 點(diǎn)擊一行時(shí),主控制中的主視圖必須展示相應(yīng)欄目的內(nèi)容,因此,必須實(shí)例化對(duì)應(yīng)點(diǎn)擊的行的欄目控制器,并用添加到導(dǎo)航控制器,調(diào)用代理 的方法傳遞數(shù)據(jù)給代理 使用,此處的代理 其實(shí)就是 主控制器
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 先取消默認(rèn)的點(diǎn)擊 高亮的顏色
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// 取出對(duì)應(yīng)行的數(shù)據(jù)模型(欄目)
Column *column = _arr[indexPath.row];
if ([self.delegate respondsToSelector:@selector(leftTableViewRowClicked:)]) {
// 傳遞數(shù)據(jù)給主控制器 BeyondViewController,通過(guò)代理
// 關(guān)鍵代碼~
[self.delegate leftTableViewRowClicked:column];
}
}
@end
RightViewController.xib

NewsViewController.xib

PicViewController.xib

CommentViewController.xib

- IOS中MMDrawerController第三方抽屜效果的基本使用示例
- iOS實(shí)現(xiàn)簡(jiǎn)單的抽屜效果
- iOS實(shí)現(xiàn)側(cè)拉欄抽屜效果
- IOS中Swift仿QQ最新版抽屜側(cè)滑和彈框視圖
- iOS實(shí)現(xiàn)左右拖動(dòng)抽屜效果
- IOS實(shí)現(xiàn)點(diǎn)擊滑動(dòng)抽屜效果
- ios仿側(cè)邊抽屜效果實(shí)現(xiàn)代碼
- iOS實(shí)現(xiàn)簡(jiǎn)單抽屜效果
- iOS實(shí)現(xiàn)簡(jiǎn)易抽屜效果、雙邊抽屜效果
- iOS簡(jiǎn)單抽屜效果的實(shí)現(xiàn)方法
相關(guān)文章
淺談iOS解析HTMl標(biāo)簽以及開發(fā)中的一些坑
這篇文章主要介紹了淺談iOS解析HTMl標(biāo)簽以及開發(fā)中的一些坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
iOS實(shí)現(xiàn)去除html標(biāo)簽的方法匯總
相信大家在做網(wǎng)站的時(shí)候,經(jīng)常會(huì)遇到去除html標(biāo)簽的問(wèn)題,下面這篇文章主要給大家總結(jié)介紹了關(guān)于iOS如何實(shí)現(xiàn)去除html標(biāo)簽的一些方法,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-10-10
iOS動(dòng)畫實(shí)現(xiàn)雨花與櫻花特效
小編今天為大家?guī)?lái)一場(chǎng)淅淅瀝瀝的夜空之雨和滿天飛舞的櫻花之戀,希望能在炎炎夏日為您帶來(lái)一絲清爽的涼意!學(xué)習(xí)iOS動(dòng)畫的小伙伴們可以參考學(xué)習(xí)。2016-08-08
Swift和Objective-C 混編注意事項(xiàng)
這篇文章主要介紹了Swift和Objective-C 混編注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下2016-10-10
iOS App中UIPickerView選擇欄控件的使用實(shí)例解析
這篇文章主要介紹了iOS App中的UIPickerView選擇欄控件的使用,文中演示了兩個(gè)超詳細(xì)的例子,示例代碼為Objective-C,需要的朋友可以參考下2016-04-04
IOS 應(yīng)用程序管理的實(shí)現(xiàn)
這篇文章主要介紹了IOS 應(yīng)用程序管理的實(shí)現(xiàn)的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10
iOS 實(shí)現(xiàn)簡(jiǎn)單的加載等待動(dòng)畫示例(思路與實(shí)現(xiàn))
本篇文章主要介紹了iOS 實(shí)現(xiàn)簡(jiǎn)單的加載等待動(dòng)畫示例(思路與實(shí)現(xiàn)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05

