前言
- 本周开始了知乎日报的仿写(其实算到今天已经是11天了,但刚开始的时候因为太久没写这种比较大的项目了就一直拖着,写的很慢);这里用到了许多暑假学习和使用的一些知识,所以复习了以前学的一些东西
- 本周比较简单的完成了主界面的布局,主要的知识点包括定时轮播图,下拉刷新,和更新数据
- 以及manager单例封装URL和AFNetworking的网络请求 ;主线程的回调;以及SDWebimage下载图片
定时轮播图
就是最上面的那个图片轮播 ;
对于无限轮播图的实现,我在暑假的网易云仿写中就已经学习并实现,这里和之前的差不多,可以去看看
网易云仿写
定时轮播图和无限轮播图其实大差不差,两者之间也确实只有定时器有无的区别;
原理就是在定时器中添加一个模拟滑动图片的方法 ;
- 这里注意一下定时器启动和关闭的时机就行
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self.timer invalidate] ;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
self.page = scrollView.contentOffset.x / [UIScreen mainScreen].bounds.size.width ;
if (self.page == 0) {
self.page = 5 ;
scrollView.contentOffset = CGPointMake([UIScreen mainScreen].bounds.size.width * self.page, 0) ;
}
if (self.page == 6) {
self.page = 1 ;
scrollView.contentOffset = CGPointMake([UIScreen mainScreen].bounds.size.width * self.page, 0) ;
}
self.timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(timeraction) userInfo:nil repeats:YES] ;
NSRunLoop* mainloop = [NSRunLoop mainRunLoop] ;
[mainloop addTimer:self.timer forMode:NSRunLoopCommonModes] ;
}
下拉刷新以及动画设置
- 由于知乎日报要实现下拉到底刷新,所以我们可以单独留一个cell来存放加载动画 ;
- 思路的话就比较明确了,即判断下拉到底时执行一个函数,在函数中执行cell的增加,以及再次网络请求更新Model中的数据 ;
判断下拉到底:
scrollView.contentOffset.y + scrollView.frame.size.height > scrollView.contentSize.height && self.isscroll == NO
即在tableview遵守代理协议,它的- (void)scrollViewDidScroll:(UIScrollView *)scrollView方法中对上面的语句判断来是否已经拉到底部 ;
但要注意一下,我还对self.isscrll进行了判断 ,这个Bool值表示的是滑动到底后只允许方法执行一次,因为上面那个方法在滑动的过程中多次执行,如果不加这个判断就会让之后的函数多次执行 ;
对于self.isscroll:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// NSLog(@"%f",scrollView.contentSize.height) ;
[self.activityIndicator startAnimating] ;
// NSLog(@"%f",scrollView.contentOffset.y + scrollView.frame.size.height ) ;
if (scrollView.contentOffset.y + scrollView.frame.size.height > scrollView.contentSize.height && self.isscroll == NO) {
self.isscroll = YES ;
//请求新的数据
self.mModel.days++ ;
self.mModel.date = [[NSDate alloc] initWithTimeIntervalSinceNow: self.mModel.days * -3600 * 24] ;
NSDateFormatter* formatter = [[NSDateFormatter alloc] init] ;
[formatter setDateFormat:@"yyyyMMdd"] ;
NSString* datestr = [formatter stringFromDate:self.mModel.date] ;
NSString* urlstr = [NSString stringWithFormat:@"https://news-at.zhihu.com/api/4/news/before/%@",datestr] ;
NSLog(@"%@",urlstr) ;
NSURL* url = [NSURL URLWithString:urlstr] ;
[[Manager shareSingleton] NetWorkGetDataAgain:^(TestModel * _Nullable mainModel) {
NSDictionary* adict = [mainModel toDictionary] ;
[self.mModel.newsarray addObjectsFromArray:adict[@"stories"]] ;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timeraction) userInfo:nil repeats:NO] ;
NSLog(@"%lu",(unsigned long)self.mModel.newsarray.count) ;
} andError:^(NSError * _Nullable error) {
NSLog(@"Error: %@",error) ;
} andURL:url] ;
// if (self.isscroll == NO) {
// NSLog(@"%d",cnt++) ;
// self.datacount++ ;
// [self.mView.maintableview reloadData] ;
// }
}
}
- (void)timeraction {
[self.activityIndicator stopAnimating] ;
self.datacount++ ;//更新cell个数
[self.mView.maintableview reloadData] ;
[self.timer invalidate] ;
self.isscroll = NO ;
}
//对cell得更新
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {//第一类定时轮播图
return 1;
}
else if (section >= 1 && section <= 1 + self.datacount) {//常规的一组cell
return 5;
} else {//尾部留一个cell来存放刷新动画
return 1;
}
}
设置下拉动画
else {
UITableViewCell* cell = [self.mView.maintableview dequeueReusableCellWithIdentifier:@"3"] ;
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"3"] ;
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium] ;
[cell addSubview:self.activityIndicator] ;
self.activityIndicator.center = cell.center ;
//设置等待动画
}
//动画的初始化不能放外面,这样会被多次初始化,而新初始化的动画可能没被开启 ;
return cell;
}
- 如果我把动画的初始化放在if语句外面,会让动画无法显示,应为每次话到底时就会调用这个数据源方法执行一次动画的初始化,反而让本被开启动画再次被初始化而不显示动画(这个地方折磨了我好几个小时,我一直以为是我下拉判断的问题);
主线程调用
- 因为这里我还没有学到iOS中的线程问题,所以可能理解有些问题,在MvC模式里面,我们在View中完成了对UI的布局,但我们在网络请求数据后再把View添加到controller的view上发现Model是空的,所以对UI内容的补充应该再网络请求的回调函数中进行 ;但对于cell中的数据就不必再回调函数里了,应为cell得数据源方法要到cell显示的时候才会调用,这个时候网络请求已经回调完成了 ;
[[Manager shareSingleton] NetWorkGetData:^(TestModel * _Nullable mainModel) {
self.mModel.modeldict = [mainModel toDictionary] ;//应该设计到线程问题,最好在请求数据的回调的时候再访问那些数据
[self.mModel.newsarray addObjectsFromArray:self.mModel.modeldict[@"stories"]] ;
self.mModel.date = self.mModel.modeldict[@"date"] ;
NSLog(@"%@",self.mModel.date) ;
// NSLog(@"%@",self.mModel.modeldict) ;
//数据源方法只会在要显示单元格是才会调用,所以在viewload方法中不会调用数据源方法,只能将请求到的数据保存下来,在数据源方法中添加给cell
[self UI] ;
} andError:^(NSError * _Nullable error) {
NSLog(@"Error: %@",error) ;
}] ;
SWDimage下载图片
这里只是使用SDWimage的这一个方法,所以我了解的也不深入 ;
UIImageView* luboimageview = [[UIImageView alloc] initWithFrame: CGRectMake([UIScreen mainScreen].bounds.size.width * (i + 1), 0, [UIScreen mainScreen].bounds.size.width, 350) ] ;
[luboimageview sd_setImageWithURL:[NSURL URLWithString:self.mModel.modeldict[@"top_stories"][i][@"image"]]] ;
日报过程中一些点
1.新闻信息的url中stories数组和top_stories数组中的image类型不同,一个是NSString,一个是NSarray ;
不区分的话,下载图片会使系统崩掉
2.UIlabel的自动换行
self.titlelabel.numberOfLines = 0 ;//设置自动换行
self.titlelabel.lineBreakMode = NSLineBreakByWordWrapping ;//设置换行方式
3.导航栏改变颜色
UINavigationBarAppearance* appearance = [[UINavigationBarAppearance alloc] init] ;
appearance.backgroundColor = UIColor.whiteColor ;
self.navigationController.navigationBar.standardAppearance = appearance ;
self.navigationController.navigationBar.scrollEdgeAppearance = appearance ;
//设置导航栏背景颜色 ;
总结
- 比较简单的实现了我上面说的那些功能,单也有些不太好的地方,比如一次只能请求一组cell ;但比起暑假界面看上去还是好看一点了
- 下周实现点击进入和个人主页 ;