澳门皇冠金沙网站-澳门皇冠844网站

热门关键词: 澳门皇冠金沙网站,澳门皇冠844网站

iOS开发中用到的自定义控件,老司机工作中用到

后天计算了一晃日常做事中为那个奇葩的UI设计自定义的控件,上面二个个分享给大家。

一、第二个是tableView的光滑度渐变效果

第10日职责:

前天首要义务完毕优秀模块的搭建。

  1. 精湛页面包车型客车搭建
  2. 特出页面中全体分界面包车型地铁展现
  3. 日期的拍卖
  4. 销路好商讨的展现和管理
1、效果:

成都百货上千app用到了这种效用,比方歌词展现、直播间聊天记录等。大概效果如下:

图片 1WZBGradualTableView图片 2背景图片截取自天涯论坛直播,侵立删

1、效果:

卓越页面的搭建

卓越页面分为总体、录制、声音、图片、段子五个分界面,四个分界面可以由此点击导航栏上面包车型大巴titleView进行页面包车型大巴切换,也得以通过手指滑动来进行页面包车型大巴切换,所以经过剖析大家曾经能差不离明白到精粹模块的页面布局结构。

图片 3优秀页面效果图片 4优秀模块的页面布局结构

从图中得以看来,非凡调控器CLEssenceViewController的View上第一贰个ScrollView用来贮存非凡调节器的七个子调控器,多个子调控器的View并排贮存,各个View的frame为荧屏尺寸。titleView也是增多在主要调控制器上,突显在scrollView下边,保证titleView长久展现在主要调控制器的View上,不会趁着scrollView的滚动而滚动。

  1. 创设子调节器,并为卓越调整器CLEssenceViewController加多子调节器
-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
-setUpScrollView{ UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].bounds]; scrollView.backgroundColor = CLCommonColor; [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-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: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;}-setHighlighted:highlighted{ }@end

4. 接下去需求做一些作业逻辑的管理,比如当页面一呈现的时候就私下认可呈现全数页面,也就一定于点击了全方位按键。当点击别的按键时,页面切换成其他页面,并将开关置于选中状态,将事先被点击的开关置于未入选状态,并将button上面提示条移动到近来button上面。当手指滑动分界面实行切换分界面时,也将相应的按键置于选中状态,尾部提示条移动到当选按键,以前的按键撤消选中状态。页面包车型客车滑行切换要求用到ScrollView的代办方法对页面包车型地铁滑动举办判别。点击button切换分界面

// 标题button点击事件-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产生滚动动画,动画结束时才会调用-scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{ [self addChildVcView];}// 减速完成 也就是滑动完成-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就不去加载他。如图所示

图片 5View的懒加载

从图中能够看到,点击了图片分界面,只加载了图片分界面,不过别的八个录制、音频、段子调节器的View并不曾加载。也正是当点击了button或然滑动分界面之后,在根据scrollView的偏移量推断必要加载哪个调整器的View,然后将View增加到scrollView中。

// 添加子控制器-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]; }

留神:这里或然会有七个吸引,我们在button点击事件卯月scrllView的滑行代理方法中都有将子调控器View增添到scrollView即[self.scrollView addSubview:childVc.view];,那岂不是每回点击button可能滑动都会重复加多贰个子调控器View到scrollView上?其实这里add方法是不会再也增加的,就算加上数不胜数次也只会加多三回。

到现在,精粹分界面包车型地铁搭建已经主导完结,接下去要做的正是内容的显得,以及内容中有的细节之处的设置。下边先来实现全部分界面包车型客车内容呈现,因为整个界面包涵录制,音频,图片,段子多个分界面全体内容,将总体分界面展现完全,别的分界面就极其简单了。

2、使用办法:
/* * frame:tableView的frame * direction:透明渐进的方向 * gradualValue:透明范围值,如果只有一个方向,此值传一个NSNumber、NSString即可,值的范围0—1。如果是两个方向,则需要传一个数组,数组里边传两个NSNumber或者NSString ***/  (instancetype)gradualTableViewWithFrame:frame direction:(WZBTableViewGradualDirection)direction gradualValue:gradualValue;

参数值说雅培(Abbott)下,direction代表方向,是二个位移枚举,假设想让tableView顶端渐变,则此值为WZBTableViewGradualDirectionTop,假如为尾部渐变,则此值为WZBTableViewGradualDirectionBottom,借使前后都要渐变,则要求WZBTableViewGradualDirectionTop | WZBTableViewGradualDirectionBottom。gradualValue代表渐变范围值,值的限定为0-1,假使想让最上部五分之一渐变,此值为@。假若想顶上部分后面部分都有五分之二渐变,此值为@[@, @]。

如下:

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

则显得效果为:

图片 6WZBGradualTableView

假设那样写

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

效率如下:

图片 7背景图片截取自网易直播,侵立删

重重app用到了这种意义,比方歌词展现、直播间聊天记录等。

经典页面中全体界面包车型地铁显得

自定义cell的分析,因为任何页面中有4种cell,4种cell顶端和尾部都以同等的仅仅中间地方不平等。这里自定义cell有三种方案。

  1. 运用持续,父类cell展现顶上部分和尾巴部分等局部完全一样的控件,中间内容由各样类型差别的cell承继父类本人体现,那样做作用独立清晰,每个cell显示本人中间内容就能够,不过这种方法未有主意使用xib来描述cell,供给使用纯代码。
  2. 一体采用一种cell,先将最上端后面部分描述出来,中间差异的位寄存怎么,视景况而定,中间有些在代码中动态增进。

因为cellNene容相当多,何况需求丰硕约束,这里运用第三种格局,下图为cell的xib布局

图片 8cell的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,通过重写-prepare措施对刷新控件实香港行政局部天性化设置。这里拿CLRefreshHeader比方,CLRefreshFooter相同CLRefreshHeader.m

#import "CLRefreshHeader.h"@implementation CLRefreshHeader-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展现内容就可以。

// 开始滑动- scrollViewDidScroll:(UIScrollView *)scrollView{ if (scrollView.contentInset.top == 149) return; if (scrollView.contentOffset.y <= - 149.0) { self.label.text = @"松开立即刷新"; } else { self.label.text = @"下拉可以刷新"; }}// 滑动结束- scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate: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, (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,上拉和下拉还要现身时,撤废当中四个。
  2. 动用AFN manager manager.tasks 里面装着独具央求,遍历撤废。
  3. 使用[manager.task makeobjectsPerformSelect:@selsct];数组方法,让数组里面全体目的都进行这些办法
  4. [manager invalidateSessionCanceingTask:YES]吧session给杀死并且撤除任务,那样表示manager未来不曾章程发送央浼了 。

科普分页情形

  1. 出殡page参数 : page = 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必要的第2页数据为 == @[15, 14, 13, 12, 11]。

自然二种分页方法影响并非常小,要基于服务器再次来到的数量,鲜明分页央浼方法。

央求新数据

-loadNewTopics{ // 数组里面的task全部取消 [self.manager.tasks makeObjectsPerformSelector:@selector]; 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]; }];}

加载更加多多少

-loadMoreTopics{ // 数组里面的task全部取消 [self.manager.tasks makeObjectsPerformSelector:@selector]; 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的使用非常轻松,右上角越来越多按键点击事件

- 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时,就显得顶,恐怕踩等汉字。收取三个主意来拍卖。

-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类时调用一次 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)-isThisYear{ NSCalendar *calendar = [NSCalendar calendar]; NSInteger creatYear = [calendar component:NSCalendarUnitYear fromDate:self]; NSInteger nowYear = [calendar component:NSCalendarUnitYear fromDate:[NSDate date]]; return creatYear == nowYear;}-isToday{ NSDateFormatter *fmt = [[NSDateFormatter alloc]init]; fmt.dateFormat = @"yyyyMMdd"; NSString *creatStr = [fmt stringFromDate:self]; NSString *nowStr = [fmt stringFromDate:[NSDate date]]; return [creatStr isEqualToString:nowStr]; }-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 得到相比较的结果。

神蹟服务器重返的小时数额恐怕是时间戳,时间戳表示从壹玖陆捌年11月1号 00:00:00开首走过的阿秒数。可以透过dateWithTimeIntervalSince1970将时间戳转化为日期时间。

设若回到的是别的区域的年月,也能够通过NSDateFormatter的locale来设置语言区域

// 设置语言区域(因为这种时间是欧美常用时间)fmt.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
3、完毕大致原理:

这种渐变效果首要用到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,那时候要求调用的代码为:

- observeValueForKeyPath:(NSString *)keyPath ofObject:object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:context { if ([keyPath isEqualToString:@"contentOffset"]) { [self change]; }}- 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];}

别忘了移除观望者:

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

大约效果如下:

人心向背切磋的来得和拍卖

看好批评不是每一条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; }

此地有三个注意点,当最热商讨是语音的时候,topic.top_cmt.content;值是为空的,这里要求提示客商最热批评是一条语音。

4、GitHub源码地址:WZBGradualTableView

图片 10

总结

前几天主要产生了经典页面包车型大巴布局,页面切换的一对逻辑管理,数据央求及上拉下拉刷新加载成功,cell内部一些细节管理。日期的管理等来看一下第二十四日的名堂吧

图片 11第八日效果图

前16日代码已经上传至github--源码下载

文中借使有畸形的地方应接提出。作者是xx_cc,二只长大十分久但还并没有二够的玩意儿。

1、效果:

图片 12WZBSwitch

图片 13

2、使用方法:

将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 - switchValueChange:(WZBSwitch *)swith on: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]}; }];

2、使用办法:

3、完结大约原理:

此控件由两有个别构成,最上端View和底部View

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

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

这些方法有七个block参数,第三个可以设置您所急需设置的全部颜色值,第三个block是当开关状态发生转移的时候回调

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

此办法用于安装开关状态

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

假如你不爱好使用block,笔者还提供了代理方法监听按钮状态的更换

- setOn:newOn animated: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  { // 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就可以

/*

4、GitHub源码地址:WZBSwitch

* frame:tableView的frame

1、效果:

图片 14WZBSegmentedControl

* direction:透明渐进的方向

2、使用方法:

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

在要求利用的地点调用

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

* gradualValue:透明范围值,假设只有多少个方向,此值传两个NSNumber、NSString就能够,值的范围0—1。若是是五个方向,则供给传贰个数组,数组里边传八个NSNumber或然NSString

3、实现大概原理:

此控件还不是很周密,如今只提供二个起首化方法:

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

- setContentOffset: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的文字也会趁机渐变,近年来先试用这么些措施一时解决,后续会提供方式设置文字颜色、选普通话字颜色、背景颜色以及滑块颜色等。

***/

4、GitHub源码地址:WZBSegmentedControl

----------------------------------难道笔者是分水线-----------------------------

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

11月13日更新:

本篇小说最终三个内容由于当下太焦急写的不完全,前几天补充一下。扩张了多少个法子设置内部控件颜色

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

有了那几个情势您就能够愉悦的用有滋有味的水彩了

图片 15本领交换群: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(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- segmentedValueDidChange:(WZBSegmentedControl *)segment selectIndex:(NSInteger)selectIndex;// segmented点击的时候调用,selectIndex:选中的index,fromeIndex:从哪个index点过来的- segmentedValueDidChange:(WZBSegmentedControl *)segment selectIndex:(NSInteger)selectIndex fromeIndex:(NSInteger)fromeIndex;// segmented点击的时候调用,selectIndex:选中的index,fromeIndex:从哪个index点过来的,selectButton:选中的button- segmentedValueDidChange:(WZBSegmentedControl *)segment selectIndex:(NSInteger)selectIndex fromeIndex:(NSInteger)fromeIndex selectButton:(UIButton *)selectButton;// segmented点击的时候调用,selectIndex:选中的index,fromeIndex:从哪个index点过来的,selectButton:选中的button,allButtons:所有的button- 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]; // 宽,高,内存中像素的每个组件的位数,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; CGColorSpaceRelease; for (NSInteger i = 0; i < 3; i  ) { colorArr[i] = data[i]; }}

那是写的多少个c语言函数,每句基本都有注释,说白了正是把RubiconGB颜色拆分开,福睿斯是稍微,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和尾部滑块交叉区域的上涨的幅度比例,切换每种Enclave、G、B的值,具体咱们能够下载最新的源码

想看越多,请点击:干货!老驾车职员和工人作中用到的自定义控件,总有三个适合您的

怎么着,那一个你学会怎么用了啊?

请不要珍爱,随手点个喜欢依旧关怀一下吗!您的辅助是自家最大的引力!此类别作品每每更新,您能够关注作者以便及时查看自身的流行篇章或许你还是能参与大家的群,大家开庭日期待您的步入!

图片 16大家的社区

参数值说多美滋(Dumex)(Nutrilon)下,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]];

图片 17

一经这么写

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

图片 18

3、完成大概原理:

这种渐变效果首要用到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"];

本文由澳门皇冠金沙网站发布于编辑程序,转载请注明出处:iOS开发中用到的自定义控件,老司机工作中用到