当前位置: 首页 > article >正文

知乎日报——第二周

知乎日报——第二周

文章目录

  • 知乎日报——第二周
    • 本周总结
    • Model
    • View
    • Controller
      • 无限右滑
      • 预加载
    • 总结

本周总结

本周主要完成了知乎日报的详情页面,实现了无限右滑和动态申请详情页的内容,实现了预先加载。以及通过位置获取相应的格外信息,使用字典进行缓存的相关操作。大致内容如下

Nov-22-2024 11-49-20

Model

首先是相关的model建立,显示相关的新闻的详细信息以及点赞数量,我是使用了一个extraInfo和一个DetailNews的类

DetailNews

这个类主要存储的是对应新闻ID的详细信息

#import <Foundation/Foundation.h>
#import "YYModel.h"
NS_ASSUME_NONNULL_BEGIN

@interface DetailNews : NSObject<YYModel>
@property (nonatomic, copy) NSString *title;          // 标题
@property (nonatomic, copy) NSString *body;           // 正文内容
@property (nonatomic, copy) NSString *imageURL;       // 主图链接
@property (nonatomic, copy) NSString *newsID;       // 分享链接
@property (nonatomic, copy) NSString *originURL;      // 原文链接
@property (nonatomic, copy) NSArray *images;        // 其他图像链接
@property (nonatomic, copy) NSString *imageHue;       // 图像色调
@end

extraInfo

这个类主要是用于存储当前页面的评论和点赞的相关信息

#import <Foundation/Foundation.h>
#import "YYModel.h"
NS_ASSUME_NONNULL_BEGIN

@interface extraInfo : NSObject<YYModel,NSCopying>
@property (nonatomic, copy) NSString *newsID;
@property (nonatomic, copy) NSString *newsTopic;
@property (nonatomic, copy) NSString *newsIamge;
@property (nonatomic, assign) NSInteger longComments;
@property (nonatomic, assign) NSInteger popularity;
@property (nonatomic, assign) NSInteger shortComments;
@property (nonatomic, assign) NSInteger comments;

@property (nonatomic, assign) BOOL isLiked;
@property (nonatomic, assign) BOOL isFavorited;
@end

NS_ASSUME_NONNULL_END

两个BOOL类型的属性使用来存储相关的点赞和收藏状态的,当滚动视图滑动到对应的视图的时候进行调用可以展示点赞状态

View

控制器的主体有分为展示内容的ScrollView和下层展示对应新闻数据的BottomView

BottomView的具体内容如下



#import <UIKit/UIKit.h>
#import "BottomViewDelegate.h"

@class extraInfo;
NS_ASSUME_NONNULL_BEGIN

@interface BottomView : UIView
@property (strong, nonatomic) UIButton *back;
@property (strong, nonatomic) UIButton *like;
@property (strong, nonatomic) UIButton *comment;
@property (strong, nonatomic) UIButton *star;
@property (strong, nonatomic) UIStackView *stackView;
@property (strong, nonatomic) extraInfo *info;
@property (strong, nonatomic) NSMutableArray *isSelected;

@property (nonatomic, weak) id<BottomViewDelegate> delegate;
@end

NS_ASSUME_NONNULL_END

#import "BottomView.h"
#import "extraInfo.h"
#import "BottomViewDelegate.h"

#import "Masonry.h"
#import "DBTool.h"
@implementation BottomView
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setupView];
    }
    return self;
}

//当获取到当前位置的extraInfo就进行布局
-(void)setInfo:(extraInfo *)info {
    _info = info;
    NSLog(@"%ld",info.popularity);
    [self.like setTitle:[NSString stringWithFormat:@"%ld",info.popularity] forState:UIControlStateNormal];
    [self.like setSelected:info.isLiked];
    [self.star setSelected:info.isFavorited];
    [self.like setTitle:[NSString stringWithFormat:@"%ld",info.popularity + 1] forState:UIControlStateSelected];
    [self.comment setTitle:[NSString stringWithFormat:@"%ld",info.comments] forState:UIControlStateNormal]  ;
}

-(void)setupView {
    self.backgroundColor = [UIColor colorWithRed:246.0 / 256.0 green:246.0 / 256.0 blue:246.0 / 256.0 alpha:1];
    
    self.stackView = [[UIStackView alloc] init];
    self.stackView.axis = UILayoutConstraintAxisHorizontal;
    self.stackView.distribution = UIStackViewDistributionEqualSpacing;
    self.stackView.alignment = UIStackViewAlignmentLeading;
    [self addSubview: self.stackView];
    
    [self.stackView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self).offset(20);
        make.right.equalTo(self).offset(-35);
        make.top.equalTo(self).offset(15);
        make.height.equalTo(@30);
    }];
    
    self.like = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.like setImage:[UIImage imageNamed:@"dianzan-2.png"] forState:UIControlStateNormal];
    [self.like setImage:[UIImage imageNamed:@"dianzan.png"] forState:UIControlStateSelected];
    
    [self.like setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    self.like.titleEdgeInsets = UIEdgeInsetsMake(-12, -12, 0, 0);
    self.like.titleLabel.font = [UIFont systemFontOfSize:12];

    [self.like setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
    [self.like addTarget:self action:@selector(clicklike:) forControlEvents:UIControlEventTouchUpInside];
    
    self.star = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.star setImage:[UIImage imageNamed:@"shoucang.png"] forState:UIControlStateNormal];
    [self.star setImage:[UIImage imageNamed:@"shoucang-2.png"] forState:UIControlStateSelected];
    [self.star addTarget:self action:@selector(clickStar:) forControlEvents:UIControlEventTouchUpInside];
    
    self.comment = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.comment setImage:[UIImage imageNamed:@"pinglun.jpg"] forState:UIControlStateNormal];
    self.comment.titleEdgeInsets = UIEdgeInsetsMake(-15, 0, 0, 0);
    self.comment.titleLabel.font = [UIFont systemFontOfSize:12];
    [self.comment setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
    
    self.back = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.back setImage:[UIImage imageNamed:@"zuojiantou.png"] forState:UIControlStateNormal];
    
    [self.stackView addArrangedSubview:self.back];
    [self.stackView addArrangedSubview:self.comment];
    [self.stackView addArrangedSubview:self.like];
    [self.stackView addArrangedSubview:self.star];
    
    
}

-(void)clickStar:(UIButton *)sender {
    sender.selected = !sender.selected;
    self.info.isFavorited = sender.selected;

}

-(void)clicklike:(UIButton *)sender {
    sender.selected = !sender.selected;
    self.info.isLiked = sender.selected;  
}
@end
  

对应展示的滚动视图即为正常的滚动视图,其显示内容为webView,我们将申请获得的URL内容,这是webView的相关操作

@implementation DetailViewController
-(void)setDetailNews:(DetailNews *)detailNews {
    _detailNews = detailNews;
    NSURL *url = [NSURL URLWithString:self.detailNews.originURL];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    [self.webView loadRequest:request];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.webView = [[WKWebView alloc] init];
    self.webView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    [self.view addSubview:self.webView];

    [self.webView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view);
        make.right.equalTo(self.view);
        make.bottom.equalTo(self.view).offset(-120);
        make.top.equalTo(self.view);
    }];
}
@end

Controller

无限右滑

实现无限右滑,首先我们需要明确我们的操作,当我们向右滑的时候就会出现上一篇新闻,当这一天的新闻到最后一篇之后就需要到下一天的第一篇,这个过程我一开始想使用的当我们新闻即将滑动至申请的data数据末尾,大概是最后的两到三页时,进行网络申请,并且更新滚动视图,添加contentView的宽度,但是后面发现,如果我滑动的速度很快直接超过了申请网络请求的速度的话,数组就会直接越姐。

于是我更改了我的思路,在一开始将滚动视图布局的时候,大小就是当前控制器的持有的data元素大小,当我们右滑到边界的时候,直接添加五个contentView,在控制器之中的scrollViewDidEndDecelerating的协议方法之中添加一个定时器,只有暂停在当前页面0.5秒才开始进行相关的网络申请,然后我使用一个currentPage的属性来保存当前滑动的位置,右滑一次就加1,左滑一次就减1,再根据这个找到对应的元素。如果当前滚动视图的当前页对应元素无法被访问,即数组越界,那么我们就会进行网络申请,然后再申请过后再递归进行嵌套,判断是否越界,不越界就将信息显示在滚动视图当中

加入滚动视图的定时器和相关函数

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    CGFloat pageWidth = scrollView.frame.size.width;
    NSInteger newPage = (scrollView.contentOffset.x + pageWidth * 0.5) / pageWidth;
    
    
    
    if (newPage != self.currentPage) {
        self.currentPage = newPage;
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(loadCurrentPage) object:nil];
        [self performSelector:@selector(loadCurrentPage) withObject:nil afterDelay:0.5];
    }
    
    
    if (scrollView.contentOffset.x + pageWidth * 3 >= scrollView.contentSize.width - pageWidth) {
        self.total += 5;
        self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * (self.total), 0);
    }
}

根据相关位置的index进行加载

- (void)loadStoryAtIndex:(NSInteger)index {
    NSInteger currentIndex = index;
    NSInteger sectionIndex = 0;
        
    for (NSArray *sectionArray in self.data) {
        if (currentIndex < sectionArray.count) {
            break;
        } else {
            currentIndex -= sectionArray.count;
            sectionIndex++;
        }
    }
        
    if (sectionIndex >= self.data.count) {
        [self requestMoreDataAndRetryWithIndex:index];
        return;
    }
    
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentIndex inSection:sectionIndex];
    Story *story = self.data[sectionIndex][currentIndex];
    if (!self.loadedDetailViews[indexPath]) {
        
        DetailViewController *detailVC = [[DetailViewController alloc] init];
        
        CGFloat xOffset = self.view.frame.size.width * index;
        detailVC.view.frame = CGRectMake(xOffset, 0, self.view.frame.size.width, self.scrollView.frame.size.height);
        
        [self addChildViewController:detailVC];
        [self.scrollView addSubview:detailVC.view];
        
        self.loadedDetailViews[indexPath] = detailVC;
        
        [[NetworkManager sharedManager] fetchNewsDetail:story.id completion:^(DetailNews *news, NSError *error) {
            if (!error && news) {
                detailVC.detailNews = news;
            }
        }];
    }
    
    if (index == self.currentPage) {
        extraInfo *cachedInfo = [[DBTool sharedManager] fetchInfoForNewsID:story.id];
        
        if (cachedInfo) {
            [self.bottomView.like setSelected:cachedInfo.isLiked];
            [self.bottomView.star setSelected:cachedInfo.isFavorited];
        } else {
            cachedInfo = self.extraInfoCache[story.id];
            if (!cachedInfo) {
                cachedInfo = [[extraInfo alloc] init];
                cachedInfo.newsID = story.id;
                cachedInfo.newsTopic = story.title;
                cachedInfo.newsIamge = [story.images firstObject];
                cachedInfo.isLiked = NO;
                cachedInfo.isFavorited = NO;
            }
        }
    
        [[NetworkManager sharedManager] fetchNewsExtraInfo:story.id completion:^(extraInfo *info, NSError *error) {
            if (!error && info) {
                cachedInfo.comments = info.comments;
                cachedInfo.popularity = info.popularity;
                [self.bottomView setInfo:cachedInfo];
                [self.bottomView.like setSelected:cachedInfo.isLiked];
                [self.bottomView.star setSelected:cachedInfo.isFavorited];
                self.extraInfoCache[story.id] = cachedInfo;
                [[DBTool sharedManager] insertInfo:cachedInfo];
            } else {
                NSLog(@"Error fetching extra info: %@", error);
            }
        }];
    }
}

这里,我还使用一个字典作为detailNews的缓存,每当我进行一次网络请求,我就会将当前新闻的ID作为键,申请到的detailNews为对应的值,当我滑动到当前页面时,先访问字典是否有对应的值,若有则直接使用,若是没有再进行网络申请,最后再将申请到的相关内容存入字典当中

预加载

预加载想要实现的就是当我在当前页的时候会向左右两边各自先加载一页,有利于用户进行操作,避免了网络请求的相关时间,

- (void)loadCurrentPage {
    [self loadStoryAtIndex:self.currentPage];
    
    if (self.currentPage > 0) {
            [self loadStoryAtIndex:self.currentPage - 1];
    }

    [self loadStoryAtIndex:self.currentPage + 1];

}

在我们加载的函数我们传进了一个参数下标index,根据这个下标我们就可以进行对应页面的加载操作,预加载也很容易就能完成只要在翻页的时候进行loadCurrentPage的运行,改变index即可。

总结

本周完成的无限右滑以及相关的预加载等操作,确实花费了不少的时间,下个星期的目标就是完成,评论区的相关内容,用富文本以及textView完成展开评论区的相关内容。


http://www.kler.cn/a/408675.html

相关文章:

  • MATLAB的addpath和rmpath函数增加或删除路径
  • 探索 Vue的nextTick :原理剖析、使用场景及代码实践详解
  • 2024年12月Gesp七级备考知识点拾遗第一期(图的定义及遍历)
  • 图形渲染性能优化
  • ES6 模块化语法
  • 产业用机器人中的旋转花键若损伤有何影响?
  • 乐鑫ESP32物联网方案,设备人机交互技术应用,启明云端乐鑫代理商
  • Java连接MySQL数据库进行增删改查操作
  • Flink-Source的使用
  • (二)手势识别——动作模型训练【代码+数据集+python环境(免安装)+GUI系统】
  • -Dspring.profiles.active=dev与--spring.profiles.active=dev的区别
  • 默语博主的推荐:探索技术世界的旅程
  • 8、深入剖析PyTorch的state_dict、parameters、modules源码
  • GCC编译过程(预处理,编译,汇编,链接)及GCC命令
  • 如果在docker 容器中安装ros遇到的问题
  • 《MySQL 事务隔离级别详解》
  • 学习Servlet(Servlet实现方式3)
  • Knife4j快速入门
  • 【redis】哈希类型详解
  • 【pip install报SSL类错误】
  • 【Anaconda】Pycharm如何配置conda虚拟环境
  • 深入理解 JVM 中的 G1 垃圾收集器原理、算法、过程和参数配置
  • YOLOv11融合[ECCV 2018]RCAN中的RCAB模块及相关改进思路
  • _computed _destinations() 为什么模板不写()
  • 渗透测试---shell(6)if条件判断与for循环结构
  • Vue小项目(开发一个购物车)