美文网首页
iOS-通过偏移量实现上下拉刷新

iOS-通过偏移量实现上下拉刷新

作者: 长衣貌 | 来源:发表于2018-06-29 19:33 被阅读0次

    给UIView添加一个类目,用来快速获得控件的一些尺寸

    //
    //  UIView+Frame.h
    //  PDBuDeJie
    //
    //  Created by 裴铎 on 2018/6/8.
    //  Copyright © 2018年 裴铎. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface UIView (Frame)
    
    /**
     宽
     */
    @property CGFloat pd_width;
    
    /**
     高
     */
    @property CGFloat pd_height;
    
    /**
     X轴
     */
    @property CGFloat pd_x;
    
    /**
     Y轴
     */
    @property CGFloat pd_y;
    
    /**
     中心X轴
     */
    @property CGFloat pd_centerX;
    
    /**
     中心Y轴
     */
    @property CGFloat pd_centerY;
    
    @end
    
    
    //
    //  UIView+Frame.m
    //  PDBuDeJie
    //
    //  Created by 裴铎 on 2018/6/8.
    //  Copyright © 2018年 裴铎. All rights reserved.
    //
    
    #import "UIView+Frame.h"
    
    @implementation UIView (Frame)
    
    - (void)setPd_width:(CGFloat)pd_width{
        
        CGRect rect = self.frame;
        rect.size.width = pd_width;
        self.frame = rect;
    }
    
    - (CGFloat)pd_width{
        return self.frame.size.width;
    }
    
    - (void)setPd_height:(CGFloat)pd_height{
        
        CGRect rect = self.frame;
        rect.size.height = pd_height;
        self.frame = rect;
    }
    
    - (CGFloat)pd_height{
        return self.frame.size.height;
    }
    
    - (void)setPd_x:(CGFloat)pd_x{
        
        CGRect rect = self.frame;
        rect.origin.x = pd_x;
        self.frame = rect;
    }
    
    - (CGFloat)pd_x{
        return self.frame.origin.x;
    }
    
    - (void)setPd_y:(CGFloat)pd_y{
        
        CGRect rect = self.frame;
        rect.origin.y = pd_y;
        self.frame = rect;
    }
    
    - (CGFloat)pd_y{
        return self.frame.origin.y;
    }
    
    - (void)setPd_centerX:(CGFloat)pd_centerX{
        CGPoint center = self.center;
        center.x = pd_centerX;
        self.center = center;
    }
    
    - (CGFloat)pd_centerX{
        return self.center.x;
    }
    
    - (void)setPd_centerY:(CGFloat)pd_centerY{
        CGPoint center = self.center;
        center.y = pd_centerY;
        self.center = center;
    }
    
    - (CGFloat)pd_centerY{
        return self.center.y;
    }
    
    @end
    
    

    初始化上下拉刷新控件

    - (void)setupRefresh{
        
        //加载头部广告视图
        //[self setupADView];
        
        //下啦刷新视图
        UIView * headerView = [[UIView alloc] init];
        
        //很多的应用tableView头部都会添加广告,所以 Y -50 让出广告位
        headerView.frame = CGRectMake(0, - 50, self.tableView.pd_width, 50);
        
        //赋值给全局属性
        self.headerView = headerView;
        
        UILabel * headerLabel = [[UILabel alloc] init];
        headerLabel.frame = headerView.bounds;
        headerLabel.backgroundColor = [UIColor grayColor];
        headerLabel.text = @"下拉加载更多";
        headerLabel.textAlignment = NSTextAlignmentCenter;
        self.headerLabel = headerLabel;
        
        [self.headerView addSubview:self.headerLabel];
        
        //把下啦刷新的视图添加到tableView的子视图,这样不会影响tableView的contentSize
        [self.tableView addSubview:self.headerView];
        
        //上拉刷新
        UIView * footerView = [[UIView alloc] init];
        footerView.frame = CGRectMake(0, 0, self.tableView.pd_width, 35);
        self.footerView = footerView;
        
        UILabel * footerLabel = [[UILabel alloc] init];
        footerLabel.frame = footerView.bounds;
        footerLabel.backgroundColor = [UIColor grayColor];
        footerLabel.text = @"上拉加载更多";
        footerLabel.textAlignment = NSTextAlignmentCenter;
        self.footerLabel = footerLabel;
        
        [self.footerView addSubview:self.footerLabel];
        
        self.tableView.tableFooterView = self.footerView;
    }
    

    当滚动视图结束减速时触发

    - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
        
        CGFloat offsetY = - (self.tableView.contentInset.top + self.headerView.pd_height + 64);
        if (self.tableView.contentOffset.y <= offsetY) {
            //进入刷新状态
            [self headerBeginRefreshing];
        }
    }
    

    只要滚动了就调用头尾的刷新方法,在刷新方法内判断滚动到哪里了,是否开始刷新
    因为应用内有全屏穿透效果,所以头部的下拉刷新控件默认时隐藏的,当向下拖拽到一定位置才会出现

    //只要进行滚动就触发的代理方法,
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
        
        //处理header下拉刷新
        [self dealHeader];
        
        //处理footer上拉刷新
        [self dealFooter];
        
        //当tableView向下拖拽的时候,显示提示标题
        if (self.tableView.contentOffset.y < -99) {
            //当视图滚动到一定的位置显示下拉刷新提示label
            self.headerLabel.hidden = NO;
        }else{
            self.headerLabel.hidden = YES;
        }
    }
    
    

    处理上下刷新的方法,内部判断滚动的位置,和是否应该刷新

    /**
     处理header
     */
    - (void)dealHeader{
        
        //正在进行下啦刷新
        //定义布尔型变量用来判断是否正在刷新
        if (self.isHeaderRefreshing) return;
        
        //当前滚动的偏移量 <= offsetY时,证明tableView下啦刷新控件已经完全出现了
        CGFloat offsetY = - (self.tableView.contentInset.top + self.headerView.pd_height + 64);
        if (self.tableView.contentOffset.y <= offsetY) {
            self.headerLabel.text = @"松开立即刷新";
        }else{
            self.headerLabel.text = @"下拉加载新鲜事.";
            self.headerLabel.backgroundColor = [UIColor grayColor];
        }
    }
    
    /**
     处理footer
     */
    - (void)dealFooter{
        
        //如果当前tableview的内容没有加载完成就返回,防止出现tableView内没有内容,尾部的刷新直接触发了
        if (self.tableView.contentSize.height == 0) {
            return;
        }
        
        //判断如果正在刷新就返回,防止重复刷新
        if (self.isFooterRefreshing) return;
        
        //当前滚动的偏移量 > offsetY时,证明tableView的内容已经滚动完成了
        CGFloat offsetY = self.tableView.contentSize.height - self.tableView.pd_height + 49;
        
        if (self.tableView.contentOffset.y >= offsetY && self.tableView.contentOffset.y > - 90) {
            //进入刷新
            [self footerBeginRefreshing];
        }
    }
    
    

    用来给头部和尾部调用的请求数据的方法

    
    #pragma mark - 数据处理
    /**
     *  发送请求给服务器,下拉刷新数据
     */
    - (void)loadNewTopics{
        
        //创建AFN管理器对象
        AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
        
        //设置AFN的解析器类型 默认是JSON的解析器,如果解析JSON可以不写这个
        manager.responseSerializer = [[AFJSONResponseSerializer alloc] init];
        
        //拼接参数
        NSMutableDictionary * parameters = [NSMutableDictionary dictionary];
        //给网络请求的每一个参数 赋值 parameters[@"key"] = @"value";
        parameters[@"key"] = @"value";
        
        /**
         参数
         1./URL
         2./请求参数
         3./获得下载进度
         4./请求成功执行的代码块 代码block块都是在主线程执行
         5./请求失败执行的代码块
         */
        [manager GET:PDPublicURL parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
            //下载进度
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            //下载成功
            NSLog(@"%@",responseObject);        
    
            //回到主线程刷新UI界面
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.tableView reloadData];
            });
            
            //结束刷新
            [self headerEndRefreshing];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            //下载失败
            [SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试."];
            
            //结束刷新
            [self headerEndRefreshing];
        }];
    }
    
    /**
     *  发送请求给服务器,上拉加载更多数据
     */
    - (void)loadMoreTopics{
        
        //创建AFN管理器对象
        AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
        
        //设置AFN的解析器类型 默认是JSON的解析器,如果解析JSON可以不写这个
        manager.responseSerializer = [[AFJSONResponseSerializer alloc] init];
        
        //拼接参数
        NSMutableDictionary * parameters = [NSMutableDictionary dictionary];
        //给网络请求的每一个参数 赋值 parameters[@"key"] = @"value";
        parameters[@"key"] = @"value";
        
        
        /**
         参数
         1./URL
         2./请求参数
         3./获得下载进度
         4./请求成功执行的代码块 代码block块都是在主线程执行
         5./请求失败执行的代码块
         */
        [manager GET:PDPublicURL parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
            //下载进度
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            //下载成功
            
            NSLog(@"%@",responseObject);
            //回到主线程刷新UI界面
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.tableView reloadData];
            });
            
            //结束刷新
            [self footerEndRefreshing];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            //下载失败
            [SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试."];
            
            //结束刷新
            [self footerEndRefreshing];
        }];
    }
    
    

    头部和尾部开始刷新的方法,开始刷新内部必须调用结束刷新方法

    #pragma mark - header开始刷新
    - (void)headerBeginRefreshing
    {
        // 如果正在下拉刷新,直接返回
        if (self.isHeaderRefreshing) return;
        
        // 如果正在上拉刷新,直接返回
        if (self.isFooterRefreshing) return;
        
        // 进入下拉刷新状态
        self.headerLabel.text = @"正在刷新数据...";
        self.headerLabel.backgroundColor = [UIColor blueColor];
        self.headerRefreshing = YES;
        // 增加内边距
        [UIView animateWithDuration:0.3 animations:^{
            UIEdgeInsets inset = self.tableView.contentInset;
            inset.top = 85;
            self.tableView.contentInset = inset;
    
        }];
        // 修改偏移量 让tableView回到顶部刷新所有数据
        self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x,  - 149);
        
        // 发送请求给服务器,下拉刷新数据
        [self loadNewTopics];
    }
    
    - (void)headerEndRefreshing
    {
        self.headerRefreshing = NO;
        
        // 减小内边距
        [UIView animateWithDuration:0.2 animations:^{
            UIEdgeInsets inset = self.tableView.contentInset;
            inset.top = 35;
            self.tableView.contentInset = inset;
            self.headerLabel.hidden = YES;
        }];
    }
    
    #pragma mark - footer开始刷新
    - (void)footerBeginRefreshing
    {
        // 如果正在上拉刷新,直接返回
        if (self.isFooterRefreshing) return;
        
        // 如果正在下拉刷新,直接返回
        if (self.isHeaderRefreshing) return;
        
        // 进入刷新状态
        self.footerRefreshing = YES;
        self.footerLabel.text = @"正在加载更多数据...";
        
        // 发送请求给服务器,上拉加载更多数据
        [self loadMoreTopics];
    }
    
    - (void)footerEndRefreshing
    {
        //结束刷新后将显示标签和bool变量变会初始状态
        self.footerRefreshing = NO;
        self.footerLabel.text = @"上拉可以加载更多";
    }
    

    相关文章

      网友评论

          本文标题:iOS-通过偏移量实现上下拉刷新

          本文链接:https://www.haomeiwen.com/subject/zgfzyftx.html