精华模块的页面布局结构,则显示效果为

明天总计了刹那间平日干活中为那一个奇葩的UI设计自定义的控件,下边壹个个享受给大家。


壹 、第③个是tableView的折射率渐变效果

第贰日任务:

前日首要义务到位精华模块的搭建。

  1. 精华页面的搭建
  2. 精华页面中全体界面的呈现
  3. 日子的处理
  4. 人心向背评论的显示和处理

一 、第四个是tableView的折射率渐变效果

1、效果:

精华页面的搭建

精华页面分为总体、摄像、声音、图片、段子多个界面,多少个界面可以通过点击导航栏上边的titleView进行页面的切换,也可以经过手指滑动来进展页面的切换,所以经过分析大家早就能大约明白到精彩模块的页面布局结构。

图片 1

精华页面效果

图片 2

精华模块的页面布局结构

从图中可以见见,精华控制器CLEssenceViewController(以下简称主控制器)的View上首先一个ScrollView用来存放在精华控制器的八个子控制器,三个子控制器的View并排存放,各种View的frame为显示器大小。titleView也是添加在主控制器上,显示在scrollView上边,保障titleView永远突显在主控制器的View上,不会趁机scrollView的滚动而滚动。

  1. 创造子控制器,并为精华控制器CLEssenceViewController添加子控制器

-(void)setUpChildViewController
{
       CLAllViewController *all = [[CLAllViewController alloc]init];
       [self addChildViewController:all];
       CLVideoViewController *video = [[CLVideoViewController alloc]init];
       [self addChildViewController:video];
       CLVoiceViewController *voice = [[CLVoiceViewController alloc]init];
       [self addChildViewController:voice];
       CLPictureViewController *picture = [[CLPictureViewController alloc]init];
       [self addChildViewController:picture];
       CLWordViewController *word = [[CLWordViewController alloc]init];
       [self addChildViewController:word];
}
  1. 为主控制器View添加ScrollView

-(void)setUpScrollView
{
       UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].bounds];
       scrollView.backgroundColor = CLCommonColor(206);
       [self.view addSubview:scrollView];
       scrollView.pagingEnabled = YES;
       scrollView.showsHorizontalScrollIndicator = NO;
       scrollView.showsVerticalScrollIndicator = NO;
       NSInteger count = [self.childViewControllers count];
       scrollView.contentSize = CGSizeMake(self.view.cl_width * count, 0);
       scrollView.delegate = self;
       self.scrollView = scrollView;
}
  1. 为主控制器添加titleView,titleView中button使用自定义CLTitleButton,便于在自定义CLTitleButton内部安装button标题,颜色,字体大小等。此外titleView种还有指示条indicatorView。

// 为主控制器添加titleView
-(void)setUpTitlesView
{
       UIView *titleView = [[UIView alloc]initWithFrame:CGRectMake(0, 64, self.view.cl_width, 35)];
        titleView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.7];
        self.titlesView = titleView;
        CGFloat buttonW = titleView.cl_width / 5.0;
        CGFloat buttonH = titleView.cl_height;
        NSArray *titlesArr = @[@"全部",@"视频",@"声音",@"图片",@"段子"];
        NSInteger count = [titlesArr count];
        for (int i= 0; i < count ; i ++) {
            CLTitleButton *titleButton = [CLTitleButton buttonWithType:UIButtonTypeCustom];
            titleButton.tag = i;
            titleButton.frame = CGRectMake(i * buttonW, 0, buttonW, buttonH);
            [titleButton setTitle:titlesArr[i] forState:UIControlStateNormal];
            [titleButton addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];
            [titleView addSubview:titleButton];
        }
        [self.view addSubview:titleView];
        UIView *indicatorView = [[UIView alloc]init];
        // 也可以取出button selecter状态下的颜色
        // UIButton *button = titleView.subviews.lastObject;
        // indicatorView.backgroundColor = [button titleColorForState:UIControlStateSelected];
        indicatorView.backgroundColor = [UIColor redColor];
        indicatorView.cl_height = 2;
        indicatorView.cl_y = titleView.cl_height - 2;
        [titleView addSubview:indicatorView];
        self.indicatorView = indicatorView;
        // 页面一显示就选中第一个button 且不需要动画
        CLTitleButton *button = titleView.subviews.firstObject;
        [button.titleLabel sizeToFit];
        button.selected = YES;
        self.selectedButton = button;
        indicatorView.cl_width = button.titleLabel.cl_width + 6;
        indicatorView.cl_centerX = button.cl_centerX;
}

自定义CLTitleButton内部安装,通过重写覆盖序列的setHighlighted方法,来打消按钮的高亮状态

-(instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame: frame]) {
        [self setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
        [self setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
        self.titleLabel.font = [UIFont systemFontOfSize:14];
    }
    return self;
}
-(void)setHighlighted:(BOOL)highlighted
{

}
@end

4.
接下去必要做一些作业逻辑的处理
,例如(1)当页面一呈现的时候就暗许呈现全体页面,也就也就是点击了整个按钮。(2)当点击其余按钮时,页面切换成其余页面,并将按钮置于选中状态,将以前被点击的按钮置于未当选状态,并将button下边提醒条移动到现行button上边。(3)当手指滑动界面进行切换界面时,也将相应的按钮置于选中状态,底部指示条移动到当选按钮,此前的按钮撤消选中状态。页面的滑行切换须要用到ScrollView的代办方法对页面的滑行进行判定。
点击button切换界面

// 标题button点击事件
-(void)titleClick:(CLTitleButton *)button
{
    self.selectedButton.selected = NO;
    button.selected = YES;
    self.selectedButton = button;

    [UIView animateWithDuration:0.25 animations:^{
        self.indicatorView.cl_width = button.titleLabel.cl_width + 6;
        self.indicatorView.cl_centerX = button.cl_centerX;
    }];

    CGPoint offset = self.scrollView.contentOffset;
    offset.x = button.tag * self.view.cl_width;
    [self.scrollView setContentOffset:offset animated:YES];
}

ScrollView的代办方法对页面滑动的监听

#pragma mark UIScrollViewDelegate代理方法
// 滑动结束时,一定要调用[setcontentoffset animated ] 或者 [scrollerRactVisible animaated]方法让scroll产生滚动动画,动画结束时才会调用
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
     [self addChildVcView];
}
// 减速完成 也就是滑动完成
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    // 选中 点击对应的按钮
    int index = scrollView.contentOffset.x / scrollView.cl_width;
    // 添加子控制器
    [self addChildVcView];
    CLTitleButton *button = self.titlesView.subviews[index];
    [self titleClick:button];
}

留意:代理方法 didEndScrollingAnimation
一定要调用[setcontentoffset animated ]或者
[scrollerRactVisible animaated]主意让scroll发生滚动动画,动画停止时才会调用。相当于说即便调用了[setcontentoffset animated ]方法,可是如若scrollView的contentoffset并不曾改动也不会调用
didEndScrollingAnimation方法。
didEndDecelerating人手动滑动,滑动截止时才会调用。
5. 归纳优化,页面View的懒加载落成
页面加载成功显示的时候我们不得不看看任何页面的始末,不过此时却在加载成功时将多个控制器的View全体加载成功,并且出示了cell的始末,不过里面有四个页面我们并没有去看,那明明占用了大气的内存,那是从未有过必要的。因此考虑拔取控制器View的懒加载,当View要来得的时候大家才去加载他,并将View彰显在显示器上。而其余没有突显的控制器View就不去加载他。如图所示

图片 3

View的懒加载

从图中得以看到,点击了图片界面,只加载了图片界面,可是任何多少个视频、音频、段子控制器的View并没有加载。约等于当点击了button可能滑动界面之后,在依照scrollView的偏移量判断必要加载哪个控制器的View,然后将View添加到scrollView中。

// 添加子控制器
-(void)addChildVcView
{
    int index = self.scrollView.contentOffset.x / self.scrollView.cl_width;
    UIViewController *childVc = self.childViewControllers[index];
//    childVc.view.frame = CGRectMake(index * self.scrollView.cl_width, 0, self.scrollView.cl_width, self.scrollView.cl_height);
    //可以化简成一句代码
    childVc.view.frame = self.scrollView.bounds;
    [self.scrollView addSubview:childVc.view];    
}

小心:那里只怕会有2个迷惑,我们在button点击事件中和scrllView的滑动代理方法中都有将子控制器View添加到scrollView即[self.scrollView addSubview:childVc.view];,那岂不是每一遍点击button大概滑动都会再一次添加多个子控制器View到scrollView上?其实那里add方法是不会重复添加的,即使加上成千成万次也只会添加三遍。

于今,精华界面的搭建已经主导形成,接下去要做的就是内容的显示,以及内容中部分细节之处的安装。上面先来达成全套界面的情节突显,因为整个界面包罗视频,音频,图片,段子多个界面全体内容,将全体界面彰显完全,其余界面就卓殊简单了。

1、效果:

洋洋app用到了那种效应,比如歌词突显、直播间聊天记录等。
大约效果如下:

图片 4

WZBGradualTableView

图片 5

背景图片截取自腾讯网直播,侵立删

不少app用到了那种效益,比如歌词突显、直播间聊天记录等。

精华页面中全体界面的来得

自定义cell的辨析,因为全数页面中有4种cell,4种cell顶部和底部都是平等的但是中间地点不等同。那里自定义cell有二种方案。

  1. 应用持续,父类cell展现顶部和底部等片段同一的控件,中间内容由五种档次不相同的cell继承父类本身显得,这样做成效独立清晰,逐个cell呈现本身中间内容即可,不过那种措施没有章程使用xib来讲述cell,必要利用纯代码。
  2. 全副利用一种cell,先将顶部尾部描述出来,中间不等同的地点放什么,视景况而定,中间某些在代码中动态增加。

因为cell内内容相比较多,而且须求丰盛约束,那里运用第③种格局,下图为cell的xib布局

图片 6

cell的xib布局

里面添加自动布局约束是比较费心的,不过假设仔细一步一步添加,就足以约束成功,添加约束照旧多多陶冶熟稔之后照旧有好多方便之处。
整整控制器加载cell

[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([CLTopicCell class]) bundle:nil] forCellReuseIdentifier:CLTopicCellID];

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CLTopicCell *cell = [tableView dequeueReusableCellWithIdentifier:CLTopicCellID];
    cell.topic = self.topicArr[indexPath.row];
    return cell;
}

呼吁数据
请求数据利用AFN,同样给cell添加模型属性Topic,通过setTopic方法给cell上控件赋值,防止在tableView: cellForRowAtIndexPath方法中给cell控件赋值,造成代码臃肿。

下拉刷新上拉加载
系统提供了下拉刷新的措施

UIRefreshControl *control = [[UIRefreshControl alloc] init];
[control addTarget:self action:@selector(loadNewTopics:) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:control];

// 结束刷新
[control endRefreshing];

系统提供的基础代谢方法有比比皆是局限性,那里运用MJRefresh完毕下拉刷新和上拉加载,成立和谐的基础代谢控件继承自MJRefresh,通过重写-(void)prepare办法对刷新控件进行一些个性化设置。这里拿CLRefreshHeader举例,CLRefreshFooter相同
CLRefreshHeader.m

#import "CLRefreshHeader.h"
@implementation CLRefreshHeader
-(void)prepare
{
    [super prepare];
    self.automaticallyChangeAlpha = YES;
    self.lastUpdatedTimeLabel.textColor = [UIColor orangeColor];
    self.stateLabel.textColor = [UIColor orangeColor];
    [self setTitle:@"赶紧下拉吧" forState:MJRefreshStateIdle];
    [self setTitle:@"赶紧松开吧" forState:MJRefreshStatePulling];
    [self setTitle:@"正在加载数据..." forState:MJRefreshStateRefreshing];    
}

那样使用起来就格外便利了,并且易于管理,要是想要修改刷新控件的体制,只须求在CLRefreshHeader中修改就足以了。

self.tableView.mj_header = [CLRefreshHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewTopics)];
// 一显示全部界面就刷新一次
[self.tableView.mj_header beginRefreshing];
self.tableView.mj_footer = [CLRefreshFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreTopics)];  

// 请求数据完成之后关闭刷新
[self.tableView.mj_header endRefreshing];

MJRefresh内部贯彻思路,在tableView中titleView上方添加下拉刷新的View,使用scrollView代理方法监听tableView的contentOffset,当开端下拉,contentOffset改变时显得刷新View,当滑动停止并且contentOffset到达一定数值时,修改刷新View突显内容即可。

// 开始滑动
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView.contentInset.top == 149) return;
    if (scrollView.contentOffset.y <= - 149.0) {
        self.label.text = @"松开立即刷新";
    } else {
        self.label.text = @"下拉可以刷新";
    }
}
//  滑动结束
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (scrollView.contentOffset.y <= - 149.0) { // 进入下拉刷新状态
        self.label.text = @"正在刷新";
        [UIView animateWithDuration:0.5 animations:^{
            UIEdgeInsets inset = scrollView.contentInset;
            inset.top = 149;
            scrollView.contentInset = inset;
        }];
        // 停两秒滑动回去
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:0.5 animations:^{
                UIEdgeInsets inset = scrollView.contentInset;
                inset.top = 99;
                scrollView.contentInset = inset;
            }];
        });
    }
}

上拉加载和下拉刷新思路同样,有二种方案,1.
当滑动到最低端时,指示用户上拉加载更加多。2.
当滑动到最低端时,自动加载下一页内容。

并且上拉和下拉现身的标题
当大家下拉刷新的时候,在多少还不曾回去刷新成功的时候,又滑行到底层上拉加载了新数据,此时就会导致数据错乱,即使上拉加载更加多的多寡已经回到,此时下拉刷新的数据也回到了,就只剩下最新的数量了。由此当上拉和下拉同时出现的时候必须要撤除掉先起先的上拉如故下拉呼吁。

  1. 保存task,上拉和下拉并且出现时,打消其中1个。
  2. 应用AFN manager manager.tasks 里面装着全体请求,遍历取消。
  3. 使用[manager.task makeobjectsPerformSelect:@selsct(canle)];数组方法,让数组里面有着目的都实施这么些措施
  4. [manager
    invalidateSessionCanceingTask:YES]吧session给杀死并且裁撤任务,那样表示manager将来没有主意发送请求了
    (谨慎使用)。

大面积分页景况

  1. 出殡page参数 : page = 2
    加载第2页的数码,每一页几条,当得到下一页时,如若有新的多少增加到最前头,就会暴发多少再次突显。
    例:服务器数据库的数目 = @[23, 22, 21, 20, 19, 18, 17, 16, 15, 14,
    13, 12, 11, 10]历次加载5条。
    第1页数据 == @[20, 19, 18, 17, 16]
    出殡page参数 : page=2,此时有新数据到场
    第2页数据 == @[18, 17, 16, 15, 14]
    就会出现数量再度突显

  2. 出殡maxid参数: maxid = 16
    加载小于16的多少每便几条,比较谨慎,保障数据衔接性,不会重叠。maxid请求的第壹页数据为
    == @[15, 14, 13, 12, 11]。

当然三种分页方法影响并不大,要根据服务器重返的数额,显然分页请求方法。

请求新数据

-(void)loadNewTopics
{
    // 数组里面的task全部取消
    [self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
    NSMutableDictionary *parameter = [NSMutableDictionary dictionary];
    parameter[@"a"] = @"list";
    parameter[@"c"] = @"data";
    parameter[@"type"] = @"1";
    [self.manager GET:CLCommonURL parameters:parameter progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        self.maxtime = responseObject[@"info"][@"maxtime"];
        self.topicArr = [CLTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];      
        [self.tableView reloadData];
        CLLog(@"请求成功");
        // 让[刷新控件]结束刷新
        [self.tableView.mj_header endRefreshing];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        CLLog(@"请求失败 -- %@",error);
        // 让[刷新控件]结束刷新
        [self.tableView.mj_header endRefreshing];
    }];
}

加载更加多多少

-(void)loadMoreTopics
{
    // 数组里面的task全部取消
    [self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
    NSMutableDictionary *parameter = [NSMutableDictionary dictionary];
    parameter[@"a"] = @"list";
    parameter[@"c"] = @"data";
    parameter[@"maxtime"] = self.maxtime;
    parameter[@"type"] = @"1";
    [self.manager GET:CLCommonURL parameters:parameter progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {  
        self.maxtime = responseObject[@"info"][@"maxtime"];
        NSArray<CLTopic *> *moreTopics = [CLTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
        [self.topicArr addObjectsFromArray:moreTopics];
        [self.tableView reloadData];
        CLLog(@"请求成功");
        // 让[刷新控件]结束刷新
        [self.tableView.mj_footer endRefreshing];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        CLLog(@"请求失败 -- %@",error);
        // 让[刷新控件]结束刷新
        [self.tableView.mj_footer endRefreshing];
    }];
}

此时cell的顶部和尾部相同的一部分情节早已可以来得。接下来要拍卖cell内部一些细节难点。
UIAlertController的简约利用
iOS8 之后UIAlertController的施用极度简单,右上角更多按钮点击事件

- (IBAction)moreClick {
    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"弹出消息标题" message:@"弹出消息内容" preferredStyle:UIAlertControllerStyleActionSheet];
    [controller addAction:[UIAlertAction actionWithTitle:@"收藏" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        CLLog(@"点击了【收藏】");
    }]];
    [controller addAction:[UIAlertAction actionWithTitle:@"举报" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        CLLog(@"点击了【举报】");
    }]];
    [controller addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        CLLog(@"点击了【取消】");
    }]];
    [self.window.rootViewController presentViewController:controller animated:YES completion:nil];
}

顶、踩等数据的浮现的处理
例:当数码超越1万时,会显示1.1万,当小于1万时就显得具体数字,当为0时,就显得顶,恐怕踩等汉字。抽取贰个措施来处理。

-(void)setUpButton:(UIButton *)button Number:(NSInteger)number Placeholder:(NSString *)placeholder
{
    NSString *strNum = [NSString string];
    if (number >= 10000) {
        strNum = [NSString stringWithFormat:@"%.1f万",number / 10000.0];
    }else if (number == 0){
        strNum = placeholder;
    }else{
        strNum = [NSString stringWithFormat:@"%zd",number];
    }
    [button setTitle:strNum forState:UIControlStateNormal];
}

日鼠时间的处理
系统重临的岁月是yyyy-MM-dd HH-mm-ss格式的,大家须要对它进行部分拍卖
看清是或不是 二〇一九年
判定是或不是 后天
看清时间距离 >= 1小时 – @”5钟头前”
1钟头 > 时间间隔 >= 1分钟 – @”10秒钟前”
1分钟 > 分钟 – @”刚刚”
昨天 – @”昨天 09:10:05″
其他 – @”11-20 09:10:05″
非今年 – @”2015-11-20 09:10:05″

在模型中重写时间created_at的get方法,先将时刻处理好,然后在突显在cell上

// 日期的处理
-(NSString *)created_at
{
    fmt_.dateFormat = @"yyyy-MM-dd HH-mm-ss";
    NSDate *createdAtDate =  [fmt_ dateFromString:_created_at];
    if (createdAtDate.isThisYear) {// 是今年
        // 判断是否是今天和昨天的方法是iOS8 才有的,如果需要适配iOS7 我们可以自己在分类中实现判断是否为今天和昨天
        if (createdAtDate.isToday) {// 是今天
            // 手机当前时间
            NSDate *nowDate = [NSDate date];
            NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
            NSDateComponents *cmps = [calendar_ components:unit fromDate:createdAtDate toDate:nowDate options:0];
            if (cmps.hour >= 1) {// 时间间隔大于一个小时
                return [NSString stringWithFormat:@"%zd小时前",cmps.hour];
            }else if (cmps.minute >= 1){
                return [NSString stringWithFormat:@"%zd分钟前",cmps.minute];
            }else{
                return @"刚刚";
            }
        }else if (createdAtDate.isYesterday){ //是昨天
            fmt_.dateFormat = @"昨天 HH:mm:ss";
            return [fmt_ stringFromDate:createdAtDate];  
        }else{
            fmt_.dateFormat = @"MM-dd HH:mm:ss";
            return [fmt_ stringFromDate:createdAtDate];
        }
    }else{ // 不是今年,直接返回直接即可
        return _created_at;
    }
    return nil;
}

created_at的get方法调用万分频仍,而NSDateFormatter和NSCalendar对象没有要求那样频仍的开创,可以动用懒加载,也得以再initialize方法中创立,initialize方法只在类加载时调用五遍。

static NSCalendar *calendar_ ;
static NSDateFormatter *fmt_;
//第一次使用CLTopic类时调用一次
+(void)initialize
{
    calendar_ = [NSCalendar calendar];
    fmt_ = [[NSDateFormatter alloc]init];
}

NScalendar的单例方法[NSCalendar currentCalendar]在iOS8事后偶然会生出错误,iOS8从此接纳[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];主意,为了适配iOS8事先版本,大家为NScalendar添加分类,添加calendar类方法依照差别版本成立calendar

+(instancetype)calendar
{
    if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
        return [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
    }else{
        return [NSCalendar currentCalendar];
    }
}

同等,系统在iOS8从此提供了判断是还是不是是前几天,明天的艺术
[calendar isDateInToday:createdAtDate];
[calendar isDateInYesterday:createdAtDate];
为了适配iOS8事先版本,我们透过给Data添加分类,自己完结判断是不是是后天和今天

#import "NSDate+CLExtension.h"

@implementation NSDate (CLExtension)

-(BOOL)isThisYear
{
    NSCalendar *calendar = [NSCalendar calendar];
    NSInteger creatYear = [calendar component:NSCalendarUnitYear fromDate:self];
    NSInteger nowYear = [calendar component:NSCalendarUnitYear fromDate:[NSDate date]];
    return creatYear == nowYear;
}
-(BOOL)isToday
{
    NSDateFormatter *fmt = [[NSDateFormatter alloc]init];
    fmt.dateFormat = @"yyyyMMdd";
    NSString *creatStr = [fmt stringFromDate:self];
    NSString *nowStr = [fmt stringFromDate:[NSDate date]];
    return [creatStr isEqualToString:nowStr]; 
}
-(BOOL)isYesterday
{
    NSDateFormatter *fmt = [[NSDateFormatter alloc]init];
    fmt.dateFormat = @"yyyyMMdd";
    NSString *creatStr = [fmt stringFromDate:self];
    NSString *nowStr = [fmt stringFromDate:[NSDate date]];
    NSDate *creatDate = [fmt dateFromString:creatStr];
    NSDate *nowDate = [fmt dateFromString:nowStr];
    NSCalendar *calendar = [NSCalendar calendar];
    NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
    NSDateComponents *cmp = [calendar components:unit fromDate:creatDate toDate:nowDate options:0];
    return cmp.year == 0 && cmp.month == 0 && cmp.day == 1;
   // cmp.day = -1即是判断是否是明天
   //return cmp.year == 0 && cmp.month == 0 && cmp.day == -1;
}
@end

日子的处理其实万分不难,只要熟识NSDateFormatter,NSCalendar类两者结合使用即可成功一般时间的处理。
NSDateFormatter 用来规定时间的格式,string 和date之间的互相转化。
NSCalendar 用来做时间之间的可比。七个时间点的间距为全体差值相加。
NSCalendarUnit 分明相比的情节,年,月,日等
NSDateComponents 得到相比的结果。

偶尔服务器重返的日子数额恐怕是时间戳,时间戳表示从1966年1九月1号
00:00:00开头走过的飞秒数。可以透过dateWithTimeIntervalSince1970将时间戳转化为日期时间。

一经回到的是其他区域的时刻,也足以经过NSDateFormatter的locale来设置语言区域

// 设置语言区域(因为这种时间是欧美常用时间)
fmt.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
贰 、使用方式:
/*
 * frame:tableView的frame
 * direction:透明渐进的方向
 * gradualValue:透明范围值,如果只有一个方向,此值传一个NSNumber、NSString即可,值的范围0—1。如果是两个方向,则需要传一个数组,数组里边传两个NSNumber或者NSString
 ***/
+ (instancetype)gradualTableViewWithFrame:(CGRect)frame direction:(WZBTableViewGradualDirection)direction gradualValue:(id)gradualValue;

参数值说Bellamy(Bellamy)下,direction代表方向,是二个位移枚举,若是想让tableView顶部渐变,则此值为WZBTableViewGradualDirectionTop,假设为底部渐变,则此值为WZBTableViewGradualDirectionBottom,要是前后都要渐变,则须求WZBTableViewGradualDirectionTop
|
WZBTableViewGradualDirectionBottom。gradualValue代表渐变范围值,值的界定为0-1,若是想让顶部百分之二十渐变,此值为@(0.2)。借使想顶部尾部都有伍分一渐变,此值为@[@(0.2),
@(0.2)]。

如下:

WZBGradualTableView *tableView = [WZBGradualTableView gradualTableViewWithFrame:self.view.bounds direction:(WZBTableViewGradualDirectionTop | WZBTableViewGradualDirectionBottom)  gradualValue:@[@(.3), @0.3]];

则突显效果为:

图片 7

WZBGradualTableView

设若如此写

[WZBGradualTableView gradualTableViewWithFrame:CGRectMake(0, self.view.frame.size.height - 180, self.view.frame.size.width, 140) direction:WZBTableViewGradualDirectionTop  gradualValue:@.3f]

功能如下:

图片 8

背景图片截取自微博直播,侵立删

大约效果如下:

看好评论的来得和拍卖

看好评论不是每一条cell都有,通过判断热门评论数组的count,判断有没有热门评论,鲜明是还是不是出示热门评论View。

图片 9

人心向背评论数据

大家须求拿到content
和user里面的username,依据面向模型开发,成立CLComment模型和CLUser模型,直接将数组内热门评论通过MJExtension字典转化为CLConmment模型。

if (topic.top_cmt) {
    self.topCmtView.hidden = NO;
    NSString *userName = topic.top_cmt.user.username;
    NSString *contentText = topic.top_cmt.content;
    if (self.top_cmt.voiceuri.length) {
         contentText = @"[语音评论]";
    }
    self.topCmtContentLabel.text = [NSString stringWithFormat:@"%@ : %@",userName,contentText];
}else{
    self.topCmtView.hidden = YES;  
}

此地有3个注意点,当最热评论是语音的时候,topic.top_cmt.content;值是为空的,那里要求指示用户最热评论是一条语音。

③ 、完毕大致原理:

那种渐变效果主要用到tableView的mask属性,大家第①要创立一个CAGradientLayer,此类的采用网上介绍有那些,在这里不再赘言,不清楚私聊小编,恐怕投入本身的技术群。

上代码:

if (!self.layer.mask) {
      CAGradientLayer *maskLayer = [CAGradientLayer layer];
      maskLayer.locations = @[@0.0, topValue, @(1-bottomValue.doubleValue), @1.0f];
      maskLayer.bounds = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
      maskLayer.anchorPoint = CGPointZero;
      self.layer.mask = maskLayer;
 }
[self addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];

出于tableView可以滑动,滑动的时候就需求实时的作出变动,因而小编这里运用KVO监听“contentOffset”属性,每当contentOffset爆发变动,申明用户滑动了tableView,那时候须求调用的代码为:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"contentOffset"]) {
        [self change];
    }
}
- (void)change {
    UIScrollView *scrollView = (UIScrollView *)self;
    CGColorRef outerColor = [UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
    CGColorRef innerColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
    NSArray *colors;

    if (scrollView.contentOffset.y + scrollView.contentInset.top <= 0) {
        //Top of scrollView
        colors = @[(__bridge id) innerColor, (__bridge id) innerColor,
                   (__bridge id) innerColor, (__bridge id) outerColor];
    } else if (scrollView.contentOffset.y + scrollView.frame.size.height
               >= scrollView.contentSize.height) {
        //Bottom of tableView
        colors = @[(__bridge id) outerColor, (__bridge id) innerColor,
                   (__bridge id) innerColor, (__bridge id) innerColor];
    } else {
        //Middle
        colors = @[(__bridge id) outerColor, (__bridge id) innerColor,
                   (__bridge id) innerColor, (__bridge id) outerColor];
    }
    ((CAGradientLayer *) scrollView.layer.mask).colors = colors;

    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    scrollView.layer.mask.position = CGPointMake(0, scrollView.contentOffset.y);
    [CATransaction commit];
}

别忘了移除观看者:

- (void)dealloc {
    [self removeObserver:self forKeyPath:@"contentOffset"];
}

图片 10

总结

前天最首要形成了精华页面的布局,页面切换的一部分逻辑处理,数据请求及上拉下拉刷新加载成功,cell内部一些细节处理。日期的拍卖等
来看一下第⑥日的收获吧

图片 11

第十日效果图

前八天代码已经上传至github–源码下载


文中尽管有狼狈的地方欢迎提议。小编是xx_cc,二头长大很久但还向来不二够的东西。

四 、GitHub源码地址:WZBGradualTableView

图片 12

② 、自定义的开关控件

二 、使用办法:

1、效果:

图片 13

WZBSwitch

/*

② 、使用方法:

将WZBSwitch.h和WZBSwitch.m拖入工程

在需求使用的地点调用

    /** 初始化方法
     *  switchValueChange: 开关状态改变回调block
     */
    WZBSwitch *switchView = [[WZBSwitch alloc] initWithFrame:CGRectMake(100, 100, 50, 25) switchValueChanged:^(WZBSwitch *swith, BOOL on)     {
        // do someing
    }];
    [self.view addSubview:switchView];

对于开关状态的监听或然您还足以透过代办:

   WZBSwitch *switchView = [[WZBSwitch alloc] initWithFrame:CGRectMake(100, 100, 50, 25)];
   [self.view addSubview:switchView];
   // delegate
   switchView.delegate = self;

然后完结代理方法即可

   #pragma mark - WZBSwitchDelegate
   - (void)switchValueChange:(WZBSwitch *)swith on:(BOOL)on {
        // do someing
   }

一经你想自定义开关颜色,代码如下:

//设置所有颜色
    [switchView setUpAllColors:^NSDictionary *(UIColor *__autoreleasing *onTintColor, UIColor *__autoreleasing *onBackgroundColor,                UIColor *__autoreleasing *offTintColor, UIColor *__autoreleasing *offBackgroundColor, UIColor *__autoreleasing *tintColor) {
        // 可以通过这种方法设置需要设置的颜色
        *onTintColor = [UIColor redColor];
        *onBackgroundColor = [UIColor blueColor];
        *offTintColor = [UIColor greenColor];
        *offBackgroundColor = [UIColor grayColor];
        *tintColor = [UIColor blackColor];
        return nil;
    }];

只怕那样

  [switchView setUpAllColors:^NSDictionary *(UIColor *__autoreleasing *onTintColor, UIColor *__autoreleasing *onBackgroundColor, UIColor    *__autoreleasing *offTintColor, UIColor *__autoreleasing *offBackgroundColor, UIColor *__autoreleasing *tintColor) {
        // 也可以通过这种方法设置需要设置的颜色
        return @{OnTintColor : WZBColor(234, 67, 53), OnBackgroundColor : WZBColor(244, 161, 154), OffTintColor : WZBColor(255, 255,              255), OffBackgroundColor : WZBColor(214, 214, 214), TintColor : [UIColor colorWithRed:0.8252 green:0.8252 blue:0.8252                   alpha:1.0]};
    }];

* frame:tableView的frame

三 、落成大致原理:

此控件由两片段构成,顶部View和底部View

@property (nonatomic, strong) UIView *topView;
@property (nonatomic, strong) UIView *bottomView;

/** 一个方法设置所有颜色 && block回调
 *  switchValueChange: 开关状态改变回调block
 */
- (void)setUpAllColors:(NSDictionary *(^)(UIColor **onTintColor,UIColor **onBackgroundColor, UIColor **offTintColor, UIColor **offBackgroundColor, UIColor **tintColor))allColorBlock switchValueChanged:(SwitchValueChangeBlock)switchValueChange;;

本条主意有八个block参数,第2个可以设置您所急需设置的全体颜色值,第二个block是当开关状态暴发转移的时候回调

/** 设置开关状态, animated : 是否有动画 */
- (void)setOn:(BOOL)newOn animated:(BOOL)animated;

此办法用于安装开关状态

@protocol WZBSwitchDelegate <NSObject>
@optional
- (void)switchValueChange:(WZBSwitch *)swith on:(BOOL)on;
@end

一经你不喜欢使用block,小编还提供了代理方法监听开关状态的改观

- (void)setOn:(BOOL)newOn animated:(BOOL)animated {
//    if (_on == newOn) return;
    __block CGRect frame = self.topView.frame;
    CGFloat newX = newOn ? self.frame.size.width - self.topView.frame.size.width : 0;
    [UIView animateWithDuration:animated ? 0.2 : 0.0 animations:^{
        frame.origin.x = newX;
        self.topView.frame = frame;
        [self setSwitchColorWithStatus:newOn];
    }                completion:^(BOOL finished) {
        if (finished) {
            // delegate
            if ([self.delegate respondsToSelector:@selector(switchValueChange:on:)]) {
                [self.delegate switchValueChange:self on:newOn];
            }
            // block
            if (self.switchValueChange) {
                self.switchValueChange(self, newOn);
            }
        }
    }];
    _on = newOn;
}

当外界调用方法改变开关状态时,动画/非动画,改变上层View的frame即可

* direction:透明渐进的方向

肆 、GitHub源码地址:WZBSwitch

*
gradualValue:透明范围值,即使惟有贰个样子,此值传2个NSNumber、NSString即可,值的范围0—1。即便是三个样子,则须要传1个数组,数组里边传五个NSNumber或许NSString

三 、3个仿腾讯网的Segment

***/

1、效果:

图片 14

WZBSegmentedControl

+ (instancetype)gradualTableViewWithFrame:(CGRect)frame
direction:(WZBTableViewGradualDirection)direction
gradualValue:(id)gradualValue;

② 、使用格局:

将WZBSegmentedControl.h和WZBSegmentedControl.m拖入工程

在须求采纳的地点调用

  /** 初始化方法
   *  titles: 所有标题
   *  titleClick: 点击标题的block回调
   */
  WZBSegmentedControl *segmentedControl = [WZBSegmentedControl segmentWithFrame:(CGRect){0, 0, 170, 25} titles:[self titles] titleClick:^(NSInteger index) {
        // do soming
  }];
  self.navigationItem.titleView = segmentedControl;

参数值说雅培(Karicare)下,direction代表方向,是多少个位移枚举,如若想让tableView顶部渐变,则此值为WZBTableViewGradualDirectionTop,假如为尾部渐变,则此值为WZBTableViewGradualDirectionBottom,假使前后都要渐变,则需求WZBTableViewGradualDirectionTop
|
WZBTableViewGradualDirectionBottom。gradualValue代表渐变范围值,值的限制为0-1,若是想让顶部百分之二十渐变,此值为@(0.2)。假若想顶部底部都有伍分之一渐变,此值为@[@(0.2),
@(0.2)]。

三 、完毕大约原理:

此控件还不是很完善,近期只提供二个开端化方法:

/* 初始化方法
 * frame:控件frame
 * titleClick:点击title的时候block回调
 **/
+ (instancetype)segmentWithFrame:(CGRect)frame titles:(NSArray *)titles titleClick:(void(^)(NSInteger index))titleClick;

- (void)setContentOffset:(CGPoint)contentOffset {
    CGRect frame = self.backgroundView.frame;
    frame.origin.x = contentOffset.x;
    self.backgroundView.frame = frame;

    // 找出要操作的两个button设置颜色(目前先这样写,后续改进)
    for (UIView *v in self.subviews) {
        if ([v isKindOfClass:[UIButton class]]) {
            UIButton *button = (UIButton *)v;
            CGFloat overLapWidth = CGRectIntersection(button.frame, self.backgroundView.frame).size.width;
            NSInteger gb = 255 - overLapWidth * (255 / (self.frame.size.width / self.titles.count));
            [button setTitleColor:WZBColor(255, gb, gb) forState:UIControlStateNormal];
        }
    }
}

宗旨措施:改变底部暗青滑块的职位,不过只要留意观望,有个注意点是,在滑行的时候title的文字也会趁着渐变,近来先试用这一个方式临时化解,后续会提供格局设置文字颜色、选中文字颜色、背景颜色以及滑块颜色等。

如下:

④ 、GitHub源码地址:WZBSegmentedControl

———————————-难道作者是分割线—————————–

WZBGradualTableView *tableView = [WZBGradualTableView
gradualTableViewWithFrame:self.view.bounds
direction:(WZBTableViewGradualDirectionTop |
WZBTableViewGradualDirectionBottom)  gradualValue:@[@(.3), @0.3]];

11月13日更新:

本篇文章最后二个内容由于当时太匆忙写的不完全,今日补给一下。
扩大了多少个点子设置内部控件颜色

/* 设置文字颜色
 * normalColor:未选中的按钮文字颜色
 * selectColor:选中的按钮文字颜色
 */
- (void)setNormalColor:(UIColor *)normalColor selectColor:(UIColor *)selectColor;
/* 设置部分颜色
 * normalColor:未选中的按钮文字颜色
 * selectColor:选中的按钮文字颜色
 * edgingColor:边框颜色
 */
- (void)setNormalColor:(UIColor *)normalColor selectColor:(UIColor *)selectColor edgingColor:(UIColor *)edgingColor;
/* 设置所有颜色
 * normalColor:未选中的按钮文字颜色
 * selectColor:选中的按钮文字颜色
 * sliderColor:滑块背景颜色
 * edgingColor:边框颜色
 */
- (void)setNormalColor:(UIColor *)normalColor selectColor:(UIColor *)selectColor sliderColor:(UIColor *)sliderColor edgingColor:(UIColor *)edgingColor;
/* 设置所有属性
 * normalColor:未选中的按钮文字颜色
 * selectColor:选中的按钮文字颜色
 * sliderColor:滑块背景颜色
 * edgingColor:边框颜色
 * edgingWidth:边框宽度
 */
- (void)setNormalColor:(UIColor *)normalColor selectColor:(UIColor *)selectColor sliderColor:(UIColor *)sliderColor edgingColor:(UIColor *)edgingColor edgingWidth:(CGFloat)edgingWidth;

有了那些点子您就足以手舞足蹈的用丰盛多彩的颜色了

技术沟通群:413050745

除却还在.h放出了那么些属性

// 所有title
@property (nonatomic, strong, readonly) NSArray *titles;
// 底部的滑块
@property (nonatomic, strong, readonly) UIView *backgroundView;
// 辅助属性,当前选中的Button
@property (nonatomic, strong, readonly) UIButton *selectButton;
// 为选中的button颜色
@property (nonatomic, strong) UIColor *normalColor;
// 选中的button颜色
@property (nonatomic, strong) UIColor *selectColor;
// 滑块颜色
@property (nonatomic, strong) UIColor *sliderColor;
// 边框颜色
@property (nonatomic, strong) UIColor *edgingColor;
// 边框颜色
@property (nonatomic, assign) CGFloat edgingWidth;

以便使用者可以单独设置有个别颜色

// 点击title的block回调
@property (nonatomic, copy) void(^tClick)(NSInteger index);
// 点击title的block回调,selectButton:选中的button
@property (nonatomic, copy) void(^titleClick)(NSInteger index, UIButton *selectButton);

再有那五个block,三个block只有入选下标参数,别的二个有入选下标和当选的button八个参数

好吧!作者认同很五个人喜爱用代理而不是block,为什么不提供代理方法吧?OK,Here!

@protocol WZBSegmentedControlDelegate <NSObject>
@optional
// segmented点击的时候调用,selectIndex:选中的index
- (void)segmentedValueDidChange:(WZBSegmentedControl *)segment selectIndex:(NSInteger)selectIndex;
// segmented点击的时候调用,selectIndex:选中的index,fromeIndex:从哪个index点过来的
- (void)segmentedValueDidChange:(WZBSegmentedControl *)segment selectIndex:(NSInteger)selectIndex fromeIndex:(NSInteger)fromeIndex;
// segmented点击的时候调用,selectIndex:选中的index,fromeIndex:从哪个index点过来的,selectButton:选中的button
- (void)segmentedValueDidChange:(WZBSegmentedControl *)segment selectIndex:(NSInteger)selectIndex fromeIndex:(NSInteger)fromeIndex selectButton:(UIButton *)selectButton;
// segmented点击的时候调用,selectIndex:选中的index,fromeIndex:从哪个index点过来的,selectButton:选中的button,allButtons:所有的button
- (void)segmentedValueDidChange:(WZBSegmentedControl *)segment selectIndex:(NSInteger)selectIndex fromeIndex:(NSInteger)fromeIndex selectButton:(UIButton *)selectButton allButtons:(NSArray *)allButtons;
@end

诠释很清楚

总结给大家讲下拖动的时候颜色渐变的兑现,间接上代码

// 根据颜色拿到RGB数值
void getRGBValue(CGFloat colorArr[3], UIColor *color) {
    unsigned char data[4];
    // 宽,高,内存中像素的每个组件的位数(RGB应该为32),bitmap的每一行在内存所占的比特数
    size_t width = 1, height = 1, bitsPerComponent = 8, bytesPerRow = 4;
    // bitmap上下文使用的颜色空间
    CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
    // 指定bitmap是否包含alpha通道
    uint32_t bitmapInfo = 1;
    // 创建一个位图上下文。当你向上下文中绘制信息时,Quartz把你要绘制的信息作为位图数据绘制到指定的内存块。一个新的位图上下文的像素格式由三个参数决定:每个组件的位数,颜色空间,alpha选项。alpha值决定了绘制像素的透明性
    CGContextRef context = CGBitmapContextCreate(&data, width, height, bitsPerComponent, bytesPerRow, space, bitmapInfo);
    // 设置当前上下文中填充颜色
    CGContextSetFillColorWithColor(context, [color CGColor]);
    // 在此区域内填入当前填充颜色
    CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
    CGContextRelease(context);
    CGColorSpaceRelease(space);
    for (NSInteger i = 0; i < 3; i++) {
        colorArr[i] = data[i];
    }
}

那是写的三个c语言函数,每句基本都有注释,说白了就是把QashqaiGB颜色拆分开,本田CR-V是稍微,G是稍稍,B是稍稍,然后放数组里。

// 找出要操作的两个button设置颜色
    NSMutableArray *buttonArr = [NSMutableArray array];
    for (UIButton *button in self.allButtons) {
        CGFloat overLapWidth = CGRectIntersection(button.frame, self.backgroundView.frame).size.width;
        if (overLapWidth > 0) {
            [buttonArr addObject:button];
        }
    }

    // 切换的时候
    if (buttonArr.count > 1) {
        UIButton *leftButton = buttonArr.firstObject;
        UIButton *rightButton = buttonArr.lastObject;
        // 设置要渐变的两个button颜色
        [rightButton setTitleColor:WZBColor([self getRGBValueWithIndex:0 button:rightButton], [self getRGBValueWithIndex:1 button:rightButton], [self getRGBValueWithIndex:2 button:rightButton]) forState:UIControlStateNormal];
        [leftButton setTitleColor:WZBColor([self getRGBValueWithIndex:0 button:leftButton], [self getRGBValueWithIndex:1 button:leftButton], [self getRGBValueWithIndex:2 button:leftButton]) forState:UIControlStateNormal];
    }

先找到八个需要转移颜色的button,依照button和尾部滑块交叉区域的涨幅比例,切换逐个宝马7系、G、B的值,具体大家可以下载流行的源码

图片 15

有不懂恐怕其余难题的地点都足以在红尘评论,可能随时沟通本人,您还足以用QQ扫描底部的二维码参与大家的技艺交换群,小编在那边等着您!

想看越多,请点击:干货!老司机工作中用到的自定义控件,总有三个顺应你的(二)

怎么样,这一个你学会怎么用了呢?

请不要怜惜,随手点个喜欢只怕关心一下呢!您的支撑是自家最大的引力!
此种类小说频频革新,您能够关怀自身以便及时查看本人的风靡篇章大概你还是能够参加大家的群,我们庭期待您的加盟!

图片 16

咱俩的社区

只要这么写

[WZBGradualTableView gradualTableViewWithFrame:CGRectMake(0,
self.view.frame.size.height – 180, self.view.frame.size.width, 140)
direction:WZBTableViewGradualDirectionTop  gradualValue:@.3f]

图片 17

③ 、完毕大概原理:

那种渐变效果首要用到tableView的mask属性,我们先是要创立贰个CAGradientLayer,此类的施用网上介绍有那一个,在那边不再累述,不清楚私聊作者,可能插足本身的技术群。

上代码:

if (!self.layer.mask) {

CAGradientLayer *maskLayer = [CAGradientLayer layer];

maskLayer.locations = @[@0.0, topValue, @(1-bottomValue.doubleValue),
@1.0f];

maskLayer.bounds = CGRectMake(0, 0, self.frame.size.width,
self.frame.size.height);

maskLayer.anchorPoint = CGPointZero;

self.layer.mask = maskLayer;

}

[self addObserver:self forKeyPath:@”contentOffset”
options:NSKeyValueObservingOptionNew context:nil];

是因为tableView可以滑动,滑动的时候就须要实时的作出改变,由此小编那边运用KVO监听“contentOffset”属性,每当contentOffset发生变动,注脚用户滑动了tableView,那时候要求调用的代码为:

– (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {

if ([keyPath isEqualToString:@”contentOffset”]) {

[self change];

}

}

– (void)change {

UIScrollView *scrollView = (UIScrollView *)self;

CGColorRef outerColor = [UIColor colorWithWhite:1.0
alpha:0.0].CGColor;

CGColorRef innerColor = [UIColor colorWithWhite:1.0
alpha:1.0].CGColor;

NSArray *colors;

if (scrollView.contentOffset.y + scrollView.contentInset.top =
scrollView.contentSize.height) {

//Bottom of tableView

colors = @[(__bridge id) outerColor, (__bridge id) innerColor,

(__bridge id) innerColor, (__bridge id) innerColor];

} else {

//Middle

colors = @[(__bridge id) outerColor, (__bridge id) innerColor,

(__bridge id) innerColor, (__bridge id) outerColor];

}

((CAGradientLayer *) scrollView.layer.mask).colors = colors;

[CATransaction begin];

[CATransaction setDisableActions:YES];

scrollView.layer.mask.position = CGPointMake(0,
scrollView.contentOffset.y);

[CATransaction commit];

}

别忘了移除观察者:

– (void)dealloc {

[self removeObserver:self forKeyPath:@”contentOffset”];

}

4、GitHub源码地址:https://github.com/WZBbiao/WZBGradualTableView

二 、自定义的开关控件

1、效果:

图片 18

贰 、使用方法:

将WZBSwitch.h和WZBSwitch.m拖入工程

在急需利用的地点调用

/** 开头化方法

*  switchValueChange: 开关状态改变回调block

*/

WZBSwitch *switchView = [[WZBSwitch alloc]
initWithFrame:CGRectMake(100, 100, 50, 25)
switchValueChanged:^(WZBSwitch *swith, BOOL on)    {

// do someing

}];

[self.view addSubview:switchView];

对此开关状态的监听可能您还能透过代办:

WZBSwitch *switchView = [[WZBSwitch alloc]
initWithFrame:CGRectMake(100, 100, 50, 25)];

[self.view addSubview:switchView];

// delegate

switchView.delegate = self;

接下来完毕代理方法即可

#pragma mark – WZBSwitchDelegate

– (void)switchValueChange:(WZBSwitch *)swith on:(BOOL)on {

// do someing

}

假使你想自定义开关颜色,代码如下:

//设置有着颜色

[switchView setUpAllColors:^NSDictionary *(UIColor *__autoreleasing
*onTintColor, UIColor *__autoreleasing *onBackgroundColor,         
      UIColor *__autoreleasing *offTintColor, UIColor
*__autoreleasing *offBackgroundColor, UIColor *__autoreleasing
*tintColor) {

// 可以透过那种形式设置须要设置的颜料

*onTintColor = [UIColor redColor];

*onBackgroundColor = [UIColor blueColor];

*offTintColor = [UIColor greenColor];

*offBackgroundColor = [UIColor grayColor];

*tintColor = [UIColor blackColor];

return nil;

}];

抑或那样

[switchView setUpAllColors:^NSDictionary *(UIColor *__autoreleasing
*onTintColor, UIColor *__autoreleasing *onBackgroundColor, UIColor 
  *__autoreleasing *offTintColor, UIColor *__autoreleasing
*offBackgroundColor, UIColor *__autoreleasing *tintColor) {

// 也可以因此那种艺术设置需求安装的颜色

return @{OnTintColor : WZBColor(234, 67, 53), OnBackgroundColor :
WZBColor(244, 161, 154), OffTintColor : WZBColor(255, 255,             
255), OffBackgroundColor : WZBColor(214, 214, 214), TintColor :
[UIColor colorWithRed:0.8252 green:0.8252 blue:0.8252                 
alpha:1.0]};

}];

三 、落成大致原理:

此控件由两局地构成,顶部View和底部View

@property (nonatomic, strong) UIView *topView;

@property (nonatomic, strong) UIView *bottomView;

/** 2个艺术设置有着颜色 && block回调

*  switchValueChange: 开关状态改变回调block

*/

– (void)setUpAllColors:(NSDictionary *(^)(UIColor
**onTintColor,UIColor **onBackgroundColor, UIColor **offTintColor,
UIColor **offBackgroundColor, UIColor **tintColor))allColorBlock
switchValueChanged:(SwitchValueChangeBlock)switchValueChange;;

那个主意有三个block参数,首个可以设置您所须要安装的具备颜色值,首个block是当开关状态爆发转移的时候回调

/** 设置开关状态, animated : 是或不是有动画 */

– (void)setOn:(BOOL)newOn animated:(BOOL)animated;

此方法用于安装开关状态

@protocol WZBSwitchDelegate

@optional

– (void)switchValueChange:(WZBSwitch *)swith on:(BOOL)on;

@end

倘使您不希罕使用block,作者还提供了代办方法监听开关状态的变更

– (void)setOn:(BOOL)newOn animated:(BOOL)animated {

//    if (_on == newOn) return;

__block CGRect frame = self.topView.frame;

CGFloat newX = newOn ? self.frame.size.width –
self.topView.frame.size.width : 0;

[UIView animateWithDuration:animated ? 0.2 : 0.0 animations:^{

frame.origin.x = newX;

self.topView.frame = frame;

[self setSwitchColorWithStatus:newOn];

}                completion:^(BOOL finished) {

if (finished) {

// delegate

if ([self.delegate
respondsToSelector:@selector(switchValueChange:on:)]) {

[self.delegate switchValueChange:self on:newOn];

}

// block

if (self.switchValueChange) {

self.switchValueChange(self, newOn);

}

}

}];

_on = newOn;

}

当外界调用方法改变开关状态时,动画/非动画,改变上层View的frame即可

④ 、GitHub源码地址:https://github.com/WZBbiao/WZBSwitch

③ 、三个仿今日头条的Segment

1、效果:

图片 19

② 、使用格局:

将WZBSegmentedControl.h和WZBSegmentedControl.m拖入工程

在须求使用的地方调用

/** 早先化方法

*  titles: 全部标题

*  titleClick: 点击标题的block回调

*/

WZBSegmentedControl *segmentedControl = [WZBSegmentedControl
segmentWithFrame:(CGRect){0, 0, 170, 25} titles:[self titles]
titleClick:^(NSInteger index) {

// do soming

}];

self.navigationItem.titleView = segmentedControl;

三 、完成大致原理:

此控件还不是很完美,近期只提供二个起头化方法:

/* 早先化方法

* frame:控件frame

* titleClick:点击title的时候block回调

**/

+ (instancetype)segmentWithFrame:(CGRect)frame titles:(NSArray
*)titles titleClick:(void(^)(NSInteger index))titleClick;

– (void)setContentOffset:(CGPoint)contentOffset {

CGRect frame = self.backgroundView.frame;

frame.origin.x = contentOffset.x;

self.backgroundView.frame = frame;

// 找出要操作的八个button设置颜色(近期先这么写,后续创新)

for (UIView *v in self.subviews) {

if ([v isKindOfClass:[UIButton class]]) {

UIButton *button = (UIButton *)v;

CGFloat overLapWidth = CGRectIntersection(button.frame,
self.backgroundView.frame).size.width;

NSInteger gb = 255 – overLapWidth * (255 / (self.frame.size.width /
self.titles.count));

[button setTitleColor:WZBColor(255, gb, gb)
forState:UIControlStateNormal];

}

}

}

基本措施:改变底部深木色滑块的岗位,不过一旦留意观望,有个注意点是,在滑行的时候title的文字也会趁着渐变,近年来先试用那么些措施暂且消除,后续会提供格局设置文字颜色、选中文字颜色、背景颜色以及滑块颜色等。

四 、GitHub源码地址:https://github.com/WZBbiao/WZBSegmentedControl

怎样,这几个你学会怎么用了呢?