iOS仿写仿写头条新闻页面

1,292 阅读3分钟

最近在学习了iOS的UI控件,所以写了一个新闻列表,以巩固之前学习的知识。

预览图

123.gif

首页实现

首页主要用两个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];
}

Demo地址