最近在学习了iOS的UI控件,所以写了一个新闻列表,以巩固之前学习的知识。
预览图
首页实现
首页主要用两个CollectionView联动实现新闻页面切换的效果。当点击新闻标题栏,新闻列表会跳转到相应的界面,滚动新闻列表时,上方的标题栏也会随之滚动。
//实现新闻页面滚动效果
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
//点击标题栏的标题,实现新闻页面滚动
if (self.titleCollectionView == collectionView) {
[collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
NSIndexPath *viewIndexPath = [NSIndexPath indexPathForItem:indexPath.item inSection:0];
[self.collectView scrollToItemAtIndexPath:viewIndexPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
[self.collectView reloadData];
}
}
//实现当新闻列表滚动时,新闻标题栏也会随之滚动
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if ([scrollView isEqual:self.collectView]) {
//计算偏移量
CGFloat x = scrollView.contentOffset.x;
CGFloat i = x / UIScreen.mainScreen.bounds.size.width;
[self.titleCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
}
}
数据渲染
使用NSURLSession网络请求获取网络数据,因为无法获取到头条的新闻数据,所以使用了抓包工具Charles修改网络接口返回的数据(返回本地自定义的JSON数据),使用第三方库YYModle讲获取到的数据进行模块化,然后渲染到设计好的UI界面。代码中提供了两种将数据模块化的方法,使用第三方库YYModle可以让代码看起来更加简洁。因为网络获取到的是图片的URL,所以使用第三方库SDWebImage将URL转换为图片,渲染到界面上。
- (void)requestdata:(RequestTitleData)block {
NSString *urlString = @"https://www.baidu.com/content-search.xml";
urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//GET请求
[request setHTTPMethod:@"GET"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
NSURLSessionDataTask *datatask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error == nil) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//方法一:使用YYModel处理数据,将数据模块化
YYModelList *model = [YYModelList yy_modelWithDictionary:dict];
// 方法二:将数据模块化
// NSMutableArray *listArr = @[].mutableCopy;
// for (NSDictionary *info in dic) {
// ListData *list = [[ListData alloc] init];
// [list configWithCollectionViewCell:info];
// NSLog(@"");
// [listArr addObject:list];
// }
dispatch_async(dispatch_get_main_queue(), ^{
if (block) {
block(model.data);
}
});
}
}];
[datatask resume];
}
删除功能
点击删除按钮会弹出一个删除视图,点击删除视图上的“不感兴趣”按钮,即可成功删除选中的新闻列表,要删除一个新闻列表需要首先删除该列表的数据源然后再刷新视图。
//删除delegate实现
- (void)tableViewCell:(UITableViewCell *)tableViewCell clickDeleteButton:(UIButton *)button {
DeleteTableViewCell *deleteView = [[DeleteTableViewCell alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 844)];
__weak typeof(self) wself = self;
[deleteView showDeleteView:^{
__strong typeof(wself) strongSelf = wself;
NSIndexPath *delIndexPath = [wself.tableView indexPathForCell:tableViewCell];
if(strongSelf.array.count > delIndexPath.row) {
//删除数据源
NSMutableArray *data = [wself.array mutableCopy];
[data removeObjectAtIndex:delIndexPath.row];
strongSelf.array = [data copy];
//刷新
[strongSelf.tableView reloadData];
}
}];
}
视频播放
视频播放功能用到了AVFoundation框架获取视频资源属性。视频播放器使用UICollectionView进行布局,为每一个item添加一个点击事件,当点击item时,视频开始播放。使用KVO监听播放状态。 因为播放器的生命周期是和cell绑定的,当我们点击多个cell时,会有多个播放器同时播放,为解决这个问题,使用单例来对播放器进行管理,视频只会在我们最新点击的item上播放。
- (void)playVideoWithUrl:(NSString *)videoUrl attachView:(UIView *)attachView {
[self stopPlay];
NSURL *videoURL = [NSURL URLWithString:videoUrl];
//视频资源属性
AVAsset *asset = [AVAsset assetWithURL:videoURL];
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
[self.playerItem addObserver:self forKeyPath:@"process" options:NSKeyValueObservingOptionNew context:nil];
//获取视频时长
CMTime duration = self.playerItem.duration;
CGFloat videoDuration = CMTimeGetSeconds(duration);
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
[self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
NSLog(@"播放进度: %@",@(CMTimeGetSeconds(time)));
}];
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.frame = attachView.bounds;
[attachView.layer addSublayer:self.playerLayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(handlePlay) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}