「iOS」——知乎日报第三周总结

知乎日报

前言

第三周完成了详情页的逻辑,主要写了无限右滑的逻辑,对一些UI控件进行优化。


详情页

WKWebView的学习

  • WKWebView是是苹果推崇的一个新的类,它用于将一个网页嵌套在软件里。

这个类的使用方法:

该类的实例对象需要添加导航代理,因此要遵守WKNavigationDelegate协议。

objectivec 复制代码
//初始化该实例对象
   self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(self.view.bounds.size.width * (self.load_real), 0, self.view.bounds.size.width, self.view.bounds.size.height)];

//设置代理模式
    self.webView.navigationDelegate = self;
//自适应高度
    self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth  | UIViewAutoresizingFlexibleHeight;
//获取网页的url,然后使用loadRequest方法加载网页
	NSURL *url = [NSURL URLWithString:self.array_url[self.load_real]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:request];

协议定义了一系列方法,可以监控和响应WKWebView的导航事件,常用的如下:

objectivec 复制代码
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
 //   NSLog(@"页面开始加载");
}

// 页面加载完成时调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSLog(@"页面加载完成");
}

// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
  //  NSLog(@"收到响应,决定是否跳转");
    decisionHandler(WKNavigationResponsePolicyAllow); // 允许跳转
}

// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
   // NSLog(@"发送请求,决定是否跳转");
    decisionHandler(WKNavigationActionPolicyAllow); // 允许跳转
}

// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
   // NSLog(@"页面加载失败: %@", error.localizedDescription);
}

// 接收到服务器重定向请求后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
  //  NSLog(@"接收到服务器重定向请求");
}

此处,在无限右滑中,想采用在页面开始加载调用的方法中添加代码实现预加载,但是会无限加载下去,产生bug。还在学习如何实现预加载。

无限右滑

我此处的逻辑采用点击单元格时,传入单元格的row和section以及数据数组。这样可以定位到当前数据的位置以及总共的数据数。

创建一个滚动视图,为前面所有数据留出幕布位置,调用
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView方法,计算当前位置。将所有url存入数组中,如果当前位置刚好在数组最后一个,则进行网络请求获取数据。如果不在,则当前位置就是url在数组的位置,直接进行Web的创建即可。同时维护幕布大小,每次幕布都增加一格。

主要代码:

objectivec 复制代码
//创建网页
-(void)LoadWeb
{
    self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width * (self.number_now + self.flag_scroll), self.view.bounds.size.height);
    self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(self.view.bounds.size.width * (self.load_real), 0, self.view.bounds.size.width, self.view.bounds.size.height)];
    
    self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth  | UIViewAutoresizingFlexibleHeight;
    
    self.webView.navigationDelegate = self;
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    
    [self.scrollView addSubview:self.webView];
    
    NSURL *url = [NSURL URLWithString:self.array_url[self.load_real]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:request];
    [self.set_load addObject:[NSString stringWithFormat:@"%d",self.load_real] ];
}



//滑动更新数据
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    int indext = scrollView.contentOffset.x / self.view.bounds.size.width;
    self.load_real = indext;
    if(indext >= (self.number_now +self.flag_scroll - 1)) {
        self.flag_scroll++;
    }
    if(![self.set_load containsObject:[NSString stringWithFormat:@"%d",indext]]) {
        if(indext == (self.array_url.count - 1)) {
            NSString *str_new = [NSString stringWithFormat:@"%@",self.array_date[1+self.cell_falg][@"date"]];
            [[Manger sharedSingleton] NetWorkWithTheme:^(CellModel *Model) {
                [self.array_date addObject:[Model ModelToDict:Model]];
                self.cell_falg ++;
                for(int i = 0; i < [self.array_date[1+self.cell_falg][@"stories"] count]; i++) {
                    [self.array_url addObject:self.array_date[1+self.cell_falg][@"stories"][i][@"url"] ];
                }
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self LoadWeb];
                });
            } andError:^(NSError *error) {
            } andNSString:(NSString *) str_new];            
        } else {
                        [self LoadWeb];
        }
        }
}

在详情页的数据,要更新到主页中,这里采用了通知传值的方法,将数据传到主页。

objectivec 复制代码
//WebVC
- (void)backButtonClicked {
    NSDictionary *userInfo = @{
        @"array_date": self.array_date,
        @"cell_flag": @(self.cell_falg)
    };
    
    [[NSNotificationCenter defaultCenter] postNotificationName:@"WebViewBackNotification" object:nil userInfo:userInfo];
    
    [self.navigationController popViewControllerAnimated:YES];
}

//FirstVC
    //注册通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(WebViewBack:) name:@"WebViewBackNotification" object:nil];


- (void)WebViewBack:(NSNotification *)notification {
    NSDictionary *userInfo = notification.userInfo;
    
    self.array_data = userInfo[@"array_date"];
    self.falg = [userInfo[@"cell_flag"] intValue];
    [self.tableView_First reloadData];
}

即可实现数据的传递。

小菊花控件

定义一个UIActivityIndicatorView属性实现小菊花控件。这里在刷新前强制等待一秒,用来显示菊花控件。

objectivec 复制代码
//.h文件
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator;

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    NSString *str_new = self.array_data[1+_falg][@"date"];
    if(scrollView.contentOffset.y > self.tableView_First.contentSize.height - self.view.bounds.size.height - 50) {
        // 开始加载时显示菊花控件
        [self.activityIndicator startAnimating];
        
        [[Manger sharedSingleton] NetWorkWithTheme:^(CellModel *Model) {
            // 强制等待1秒
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self.array_data addObject:[Model ModelToDict:Model]];
                self.falg++;
                
                [self.tableView_First reloadData];
                //结束菊花控件
                [self.activityIndicator stopAnimating];
            });
            
        } andError:^(NSError *error) {
            NSLog(@"xialaerror:%@",error);
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.activityIndicator stopAnimating];
            });
        } andNSString:(NSString *)str_new];
    }
}

工具栏

工具栏的按钮,可以通过设置一个UIImageView和一个Label实现。

objectivec 复制代码
    UIImageView *imageViewPL = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pinglunqu-pinglun.png"]];
    imageViewPL.frame = CGRectMake(0, 10, 30, 30);
    UILabel *labelPL = [[UILabel alloc] initWithFrame:CGRectMake(40, 0, 20, 20)];
    labelPL.text = @"7";
    UIView *viewPL = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
    [viewPL addSubview:imageViewPL];
    [viewPL addSubview:labelPL];
    UIBarButtonItem *btn_PL = [[UIBarButtonItem alloc] initWithCustomView:viewPL];
    btn_PL.width = 60;

总结

在无限右滑中,对实现预加载没什么思路,下周尽量实现了评论区等功能后,实现一下预加载功能。

相关推荐
茶底世界之下2 小时前
类型擦除之后,Metal 滤镜组合为什么不能只执行一个 Filter?
ios·swift
传奇开心果编程5 小时前
【SwiftUI提高练中学】第8课 网络层架构:拦截器、重试、缓存与离线优先
学习·macos·ui·ios·swiftui
传奇开心果编程11 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
tink13 小时前
告别 Xcode IDE:用 VS Code + SweetPad + XcodeGen 开发 iOS 应用的完整指南
ios·swiftui·xcode
传奇开心果编程14 小时前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
黑科技iOS上架16 小时前
iOS隐私合规扫描工具
ios·审核
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer
传奇开心果编程16 小时前
【Compose Multiplatform 跨端开发学与练】第2课 Compose 基础语法
android·windows·学习·ui·ios·kotlin·composer