iOS开发之路--仿网易抽屉效果

2016-02-19 11:23 20 1 收藏

下面是个超简单的iOS开发之路--仿网易抽屉效果教程,图老师小编精心挑选推荐,大家行行好,多给几个赞吧,小编吐血跪求~

【 tulaoshi.com - 编程语言 】

最终效果图:


MainStoryBoard示意图:


BeyondViewController.h

//// BeyondViewController.h// 19_抽屉效果_仿网易//// 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;// 右半边 (显示 的是个人信息设置视图)@property (weak, nonatomic) IBOutlet UIView *rightView;// 最上面,最大的全屏的是主视图@property (weak, nonatomic) IBOutlet UIView *mainView;// 上面标题状态栏视图中的标题按钮 (网易的Logo图片和栏目的名称 水平排列)@property (weak, nonatomic) IBOutlet UIButton *titleBtn;// mainView的下半部分 是 正文的view,显示子栏目的view@property (weak, nonatomic) IBOutlet UIView *contentView;// pan 拽 手势处理- (IBAction)panGesture:(UIPanGestureRecognizer *)sender;// mainView的上半部分 标题状态栏视图中的左,右按钮- (IBAction)btnClick:(UIButton *)sender;@end

BeyondViewController.m

//// BeyondViewController.m// 19_抽屉效果_仿网易//// 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// 手势结束时的x#define kEndX frame.origin.x// 左view的宽度#define kLeftWidth _leftView.frame.size.width// 右view的宽度#define kRightWidth _rightView.frame.size.width// 对协议进行提前声明@protocol LeftTableViewControllerDelegate ;@interface BeyondViewController ()LeftTableViewControllerDelegate{  // 手指按下的时候,记住,mainView的起始x  CGFloat _startX;// 成员变量,记住左边控制器的实例  LeftTableViewController *_leftVC;  // 成员变量,记住右边控制器的实例  RightViewController *_rightVC;  // 字典 ,记住所有实例化了 栏目的子控制器,避免每次都重新创建  NSMutableDictionary *_columnViewControllers;  }@end@implementation BeyondViewController// 隐藏状态栏- (BOOL)prefersStatusBarHidden{  return YES;}- (void)viewDidLoad{  [super viewDidLoad];_titleBtn.backgroundColor = [UIColor clearColor];// 0 字典 ,记住所有实例化了 栏目的子控制器,避免每次都重新创建  _columnViewControllers = [NSMutableDictionary dictionary];// 0,设置导航条bar的背景 为网 易 红  //[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"bg.png"] forBarMetrics:UIBarMetricsDefault];  // 状态条颜色 改成默认的样式  //[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;// 1,添加左边控制器的view到左边的view里面  _leftVC = [[LeftTableViewController alloc]init];  // 关键代码 为了拿到左边控制器的某一行被点击时候,对应的栏目数据模型对象,主控制器成为了左边控制器的代理,遵守了它定好的协议,实现了协议中的方法,从而拿到左边控制器被点击行号对应的数据模型对象  _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,第一次加载时候,就就应该显示新闻 子栏目的控制器到导航控制器,再将导航控制器的view添加到 mainView里面  [self firstLoading];}// 自定义方法,第一次加载时候,就就应该显示新闻 子栏目的控制器到导航控制器,再将导航控制器的view添加到 mainView里面- (void)firstLoading{  Column * column = [Column columnNamed:@"新闻" imgName:@"news.png" className:@"NewsViewController"];// 仅需手动调用一个 LeftViewController的代理 方法,leftTableViewRowClicked,传递一个新闻 子栏目即可  [self leftTableViewRowClicked:column];}// pan 拽 手势处理- (IBAction)panGesture:(UIPanGestureRecognizer *)sender{// 如果是刚按下的状态,则记住,mainView的起始x  if (UIGestureRecognizerStateBegan == sender.state) {_startX = self.mainView.frame.origin.x;  }  // 平移拖动的距离  CGPoint delta = [sender translationInView:_mainView];CGRect frame = self.mainView.frame;// 计算新的x值,并做健壮性判断  kEndX = _startX + delta.x;// 1,限制最大拖动范围if (kEndX = kLeftWidth) {kEndX = kLeftWidth;  }  if (kEndX = - kRightWidth) {kEndX = - kRightWidth;  }  // 2,由于 左view和右view在重叠,所以要隐藏其中的一个  if (kEndX  0) {// NSLog(@"--调用频率相当高--");_rightView.hidden = YES;_leftView.hidden = NO;  } else {_rightView.hidden = NO;_leftView.hidden = YES;  }  if (UIGestureRecognizerStateEnded == sender.state) {// 手势结束的时候,需进行robust判断// 2,分析end松手时候,的位置x,决定展开到什么程度/*// 2.1 如果只向右拖了一点点,小于 1/2 的左view的宽度,则归0if (kEndX  0.5*kLeftWidth && kEndX = 0) {  kEndX = 0;}else if (kEndX = 0.5*kLeftWidth && kEndX = kLeftWidth) {  // 2.2 如果向右拖一大半了,大于 1/2 的左view的宽度,虽然还没到位,也可以认为是到位了  kEndX = kLeftWidth;}else if (kEndX  - 0.5*kRightWidth && kEndX = 0) {  // 2.3 如果只向左拖了一点点,小于 1/2 的右view的宽度,则归0  kEndX = 0;}else if (kEndX = - 0.5*kRightWidth) {  // 2.4 如果向左拖一大半了,大于 1/2 的右view的宽度,虽然还没到位,也可以认为是到位了  kEndX = - kRightWidth;}*/// 第2种判断方式// 起始为0,delta.x大于0 代表向右滑动if (_startX == 0 && delta.x 0) {  kEndX = kLeftWidth;}else if (_startX == 0 && delta.x  0){  // 起始为0,delta.x小于0 代表向左滑动  kEndX = - kRightWidth;}else if (_startX == kLeftWidth && delta.x  0){  // 起始为kLeftWidth,delta.x小于0 代表向左滑动  kEndX =0;}else if (_startX == - kRightWidth && delta.x  0){  // 起始为- kRightWidth,delta.x大于0 代表向右滑动  kEndX = 0;}  }// 最后,才设置mainView的新的frame  [UIView animateWithDuration:0.2 animations:^{self.mainView.frame=frame;  }];// 最后,为mainView所在的图层 添加阴影效果  [self addShadowFormainViewWithEndX:kEndX];  }// 自定义方法,为mainView所在的图层 添加阴影效果 (调用频率相当高)- (void)addShadowFormainViewWithEndX:(CGFloat)endX{  // 1,点击工程,加号,导入第3方框架 #import QuartzCore/QuartzCore.h// 2,拿到mainView所在的图层,设置阴影 参数   // NSLog(@"调用频率很高---");  _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);  }  }// 单击按钮,也一样可以展开 左右侧边栏- (IBAction)btnClick:(UIButton *)sender{  // 定义一个临时变量  CGFloat startX = _mainView.frame.origin.x;  // 先为mainView所在的图层 添加阴影效果  [self addShadowFormainViewWithEndX:sender.tag == 1?1:-1];  // 定义一个临时变量  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;}  }  // 最后才设置mainView的x,调用抽取出来的公共代码,设置mainView的x,参数是endX  [self setmainViewX:tempEndX];}// 抽取出来的公共代码,设置mainView的x,参数是endX- (void)setmainViewX:(CGFloat)endX{  CGRect frame = self.mainView.frame;  frame.origin.x = endX;  [UIView animateWithDuration:0.2 animations:^{self.mainView.frame=frame;  }];  }// 最关键的方法,左边控制器的代理 方法,当前左边控制器中的某一行被点击的时候 会调用- (void)leftTableViewRowClicked:(id)columnSelected{  Column *column = (Column *)columnSelected;  // 1,关闭左边的控制=======================  // 调用抽取出来的公共代码,设置mainView的x,参数是endX  [self setmainViewX:0];// 2,更改标题按钮上面的文字  _titleBtn.titleLabel.text = column.columnName;// 根据栏目数据模型中的类名,实例化对应栏目的控制器,并且将其设置为导航控制器的根控制器,最后将导航控制器的view添加到mainView中,目的是方便设置导航条,以及,各控制器的跳转  // 2,从缓存字典中取,如果子控制器字典有曾经创建过的子控制器,直接取出来用  UIViewController *columnVC = _columnViewControllers[column.columnClassName];  // 如果子控制器字典中没有保存过该栏目的控制器,才要创建子控制器  if (columnVC == nil) {Class c = NSClassFromString(column.columnClassName);columnVC = [[c alloc]init];// 并且一定要将其放到 子控制器字典里面,存起来[_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导航控制器的子控制器,并将其移除(如果有的话),然后才将新的栏目对应的子控制器添加到导航控制器容器中,注意,这儿可以用字典 记住 所有的已经实例化出来 的栏目子控制器,这样就避免每次都alloc创建新的栏目子控制器,而是只需要根据类名,从字典取出上一次实例化了的同一栏目的子控制器即可  }@end

栏目数据模型Column.h

//// Column.h// 19_抽屉效果_仿网易//// Created by beyond on 14-8-1.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import Foundation/Foundation.h// 数据模型 代表一个栏目@interface Column : NSObject// 栏目名称@property (nonatomic,copy)NSString *columnName;// 栏目图片名称@property (nonatomic,copy)NSString *columnImgName;// 栏目对应的控制器的类名@property (nonatomic,copy)NSString *columnClassName;// UI控件用weak,字符串用copy,其他对象用strong// 提供一个类方法,即构造函数,返回封装好数据的对象(返回id亦可)+ (Column *)columnNamed:(NSString *)columnName imgName:(NSString*)columnImgName className:(NSString *)columnClassName;@end

栏目数据模型Column.m

//// Column.m// 19_抽屉效果_仿网易//// Created by beyond on 14-8-1.// Copyright (c) 2014年 com.beyond. All rights reserved.// 数据模型 代表一条栏目#import "Column.h"@implementation Column// 返回一个包含了 栏目对应控制器名字的 对象实例+ (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

左边控制器定义好的协议LeftTableViewControllerDelegate.h

//// LeftTableViewControllerDelegate.h// 19_抽屉效果_仿网易//// Created by beyond on 14-8-1.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import Foundation/Foundation.h#import "Column.h"// 左边控制器 定义的代理/协议 它通过调用自己的成员属性(即代理)的该方法,将数据传递出去(给它的代理去使用) (其实 是主控制器想要数据,所以主控制器在实例化左边控制器的时候,要设置左边控制器对应的代理 为 主控制器 自身)@protocol LeftTableViewControllerDelegate NSObject- (void)leftTableViewRowClicked:(Column *)columnSelected;@end

LeftTableViewController.h

//// LeftTableViewController.h// 19_抽屉效果_仿网易//// Created by beyond on 14-8-1.// Copyright (c) 2014年 com.beyond. All rights reserved.//#import UIKit/UIKit.h// 对协议进行提前声明@protocol LeftTableViewControllerDelegate;@interface LeftTableViewController : UITableViewController// 代理 用weak,防止循环问题,可以是任意类型,但必须遵守协议@property (nonatomic,weak) idLeftTableViewControllerDelegate delegate;@end

LeftTableViewController.m

//
//  LeftTableViewController.m
//  19_抽屉效果_仿网易
//
//  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 ()
{
    // 栏目数组,保存的是左边栏目列表中的所有栏目对象
    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"];
    // 以后要添加栏目,只要改这里就可以了
   
   
    // 将栏目对象,一次性全添加到不可变数组中
    _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";
    // 下面这个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];
    }
   
    // 设置独一无二的数据
    Column *column = _arr[indexPath.row];
    cell.textLabel.text = column.columnName;
    cell.imageView.image = [UIImage imageNamed:column.columnImgName];
    return cell;
}

// 点击一行时,主控制中的主视图必须展示相应栏目的内容,因此,必须实例化对应点击的行的栏目控制器,并用添加到导航控制器,调用代理 的方法传递数据给代理 使用,此处的代理 其实就是 主控制器
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 先取消默认的点击 高亮的颜色
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    // 取出对应行的数据模型(栏目)
    Column *column = _arr[indexPath.row];
   
    if ([self.delegate respondsToSelector:@selector(leftTableViewRowClicked:)]) {
       
        // 传递数据给主控制器 BeyondViewController,通过代理
        // 关键代码~
        [self.delegate leftTableViewRowClicked:column];
    }
   
   
}
@end

RightViewController.xib


NewsViewController.xib


PicViewController.xib

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)


(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

CommentViewController.xib


来源:http://www.tulaoshi.com/n/20160219/1597356.html

延伸阅读
标签: 手机软件
1. App Store排行榜调整 2014年5月24日,App Store排行榜由原来展示TOP 200调整为只展示TOP 150。6月13日,苹果又推出了“按照类别浏览”的新功能。App Store排行榜从TOP 200变成TOO 150增加了所有iOS应用上榜的难度,同时也增加了应用被用户发现的难度,这也让App Store排行榜的运营不仅成为一种技术,更成为一种...
SlidingDrawer隐藏屏外的内容,并允许用户通过handle以显示隐藏内容。它可以垂直或水平滑动,它有俩个View组成,其一是可以拖动的handle,其二是隐藏内容的View.它里面的控件必须设置布局,在布局文件中必须指定handle和content。 1、布局layou文件 代码如下: LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" a...
在iOS7之前,View Controller的切换主要有4种: Push/Pop,NavigationViewController Present and dismis Modal UITabBarController addChildViewController(一般用于自定义的继承于 UIViewController 的容器子类) iOS5,调用- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewContro...
实现类似在微信中使用的滴滴打车的progressview,实现效果如图 //// CCProgressView.h// HurricaneConsumer//// Created by wangcong on 15-3-25.// Copyright (c) 2015年 WangCong. All rights reserved.// #import UIKit/UIKit.h#import QuartzCore/QuartzCore.h /** * 动画开始 */typedef void(^block_progress_start)(); /** * 动画正...
为何学习iOS开发要先学C语言呢,学习c语言对ios开发有何作用。 现在越来越多的iOS开发兴趣爱好者投入到了iOS培训中,有的是已经在职的员工,有的是还在就读的学生,还有一些是完全零基础的同学,那么对于他们来说就要一切从基础开始学,首先从C语言学起。 因为C语言是一门语言基础,因具备简洁、灵活等特点而被广泛应用,在多种开发环境中都...

经验教程

393

收藏

34
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部