ios 自定义上拉下拉刷新

项目里面也用到了自定义。不过是网上找了别人的插件 直接用。而且不是我负责的部分。所以没有好好看看。现在有时间 自己研究一下。然后在看看别人的源代码。首先先自己尝试着写个看看。

首先的整理开发思路:我们的目标是在当tableview 下拉 或者上拉 到一定程度。松开后触发事件。

先写下拉刷新

第一步 我们需要给tableview 的上下加上 2个用于显示加载更多 字样的 (或者 其他绚丽的自定义效果的加载效果)view。并且我们要监听到这2个view 滚到到视野中,触发加载更多的事件。显示的view 直接加载tableview上面就行了。top 写成 -50(这个view的高度)就行了。然后实现scrollview 的委托方法:

self.label= [[UILabel alloc] initWithFrame:CGRectMake(0, -50, 320, 50)];
    [self.label setText:@"下拉刷新"];
    [self.tableView addSubview: self.label];

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    int y = scrollView.contentOffset.y;
    if(y<-50){
        [self.label setText:@"松开刷新"];
    }else{
        [self.label setText:@"下拉刷新"];
    }
//    NSLog(@"%d",y);
}

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
     int y = scrollView.contentOffset.y;
    NSLog(@"xxxxx---%d",y);
}
这样就简单的效果就出来。下面处理一个逻辑scrollviewenddragging方法里面做逻辑 满足条件 取刷新界面。

发现一个问题。是用力往下滑。在没有达到刷新条件的时候松开。有惯性动画 会继续往下滑动。 会造成  scrollViewDidEndDragging 里面不满足刷新条件。 scrollViewDidScroll 里面的判断逻辑却能够满足条件。 看了下资料 应该在 scrollViewDidScroll里面加上判断 if([scrollViewisDragging]) 只有手指拖动的时候才改变这些文字。

第二步 需要做的是 当加载中的时候 将界面固定住。这时候就可以用到 UIEdgeInsets 了 当加载中的时候。给个 top 为 50 的UIEdgeInsets。这样 一个简单的 下拉刷新就完成了。当然这样使用很不好用。 需要写成独立的插件。下面尝试一下 修成可以即插即用的插件。

我的思路是 既然要通用。也要支持别人更换加载中的界面。 所以作为显示的view 需要实现我定义的一些协议:比如 刷新中 界面如何显示。 刷新结束 界面如何显示等等。

在这里需要说的是,发现别人是通过 addObserver 来处理的。这样明显更好。又不影响 之前的逻辑。如果像我那样 通过scrolldelegate 来实现。那么 作为插件而言。就破坏了别人原本的逻辑。比如别人也需要监听这些行为。可能互相覆盖什么的。

对于kvo的知识我以前都不知道。现在知道了还有个这么强大的功能。现在想想 利用这个功能应该可以实现很多以前效果。

同时发现如果写成uiscrollview的分类用起来也会方便很多。不过存在一个问题。就是分类是没法加属性的。查看别人的代码。发现了一个很有意思的东西:

objc_setAssociatedObject 

导入  <objc/runtime.h> 即可以使用 objc_setAssociatedObject 这个运行时函数。可以将一个对象与另外一个对象关联。其实就实现了拓展一个类的内存。


写了一个简单的小架构。

UIScrollView+MyRefresh.h

//
//  UIScrollView+MyRefresh.h
//  test3
//
//  Created by Aurora_sgbh on 15-1-16.
//  Copyright (c) 2015年 Aurora_sgbh. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "DefaultTopLoadView.h"
@interface UIScrollView (MyRefresh)
@property(strong,nonatomic) DefaultTopLoadView *topShowView;

- (void)addTopTarget:(id)target andAction:(SEL)sel withView:(DefaultTopLoadView *)topShowView;
- (void) endRefresh;
@end

UIScrollView+MyRefresh.m

//
//  UIScrollView+MyRefresh.m
//  test3
//
//  Created by Aurora_sgbh on 15-1-16.
//  Copyright (c) 2015年 Aurora_sgbh. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "UIScrollView+MyRefresh.h"
#import "DefaultTopLoadView.h"
#import <objc/runtime.h>
@interface UIScrollView()

@end
@implementation UIScrollView (MyRefresh)
static char topShowViewChar;


//

- (void)addTopTarget:(id)target andAction:(SEL)sel withView:(DefaultTopLoadView *)topShowView{
   
    if(self.topShowView){
        [self.topShowView removeFromSuperview];
    }
    if(topShowView){
        self.topShowView = topShowView;
    }else{
        self.topShowView = [[DefaultTopLoadView alloc]initWithFrame:CGRectMake(0, -50, 320, 50)];
    }
    DefaultTopLoadView* defaultTopLoadView= self.topShowView;
    self.topShowView.action = sel;
    self.topShowView.actionTar = target;
    self.topShowView.topRefreshStatus = REFRESH_STATUS_NORMAL;
    self.topShowView.parentScrollView =self;
    [self addSubview:self.topShowView];
    
    [self addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if([keyPath isEqualToString:@"contentOffset"]){
//        NSLog(@"%@",change);
        NSValue * point = (NSValue *)[change objectForKey:@"new"];
        CGPoint p = [point CGPointValue];
//        NSLog(@"%f---%f",p.x,p.y);
//        [self.topShowView adjustStatus];
        [self.topShowView adjustStatusByTop:p.y];
    }
    //NSLog(@"%@,%@,%@,%@",keyPath,object,change,context);
}
#pragma mark---自定义实现的get set 方法来实现分类增加属性功能
-(DefaultTopLoadView *)topShowView{
    return objc_getAssociatedObject(self, &topShowViewChar);
}
-(void)setTopShowView:(DefaultTopLoadView *)topShowView{
    objc_setAssociatedObject(self, &topShowViewChar,topShowView,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)endRefresh{
    self.topShowView.topRefreshStatus = REFRESH_STATUS_NORMAL;
}

@end

DefaultTopLoadView.h

//
//  DefaultTopLoadView.h
//  test3
//
//  Created by Aurora_sgbh on 15-1-13.
//  Copyright (c) 2015年 Aurora_sgbh. All rights reserved.
//

#import <UIKit/UIKit.h>
@protocol TopViewDelegate <NSObject>
-(void) showBeforeRefresh;
@end
enum REFRESH_STATUS{
    REFRESH_STATUS_NORMAL=1,
    REFRESH_STATUS_BEFORE_REFRESH=2,
    REFRESH_STATUS_REFRESHING=3,
//    REFRESH_STATUS_NORMAL=1
};
@interface DefaultTopLoadView : UIView<TopViewDelegate>
@property(weak,nonatomic) id actionTar;
@property(assign,nonatomic) SEL action;
@property(assign,nonatomic) int topRefreshStatus;
@property(weak,nonatomic) UIScrollView *parentScrollView;
-(void)adjustStatusByTop:(float) y;
@end

//
//  DefaultTopLoadView.m
//  test3
//
//  Created by Aurora_sgbh on 15-1-13.
//  Copyright (c) 2015年 Aurora_sgbh. All rights reserved.
//

#import "DefaultTopLoadView.h"
@interface DefaultTopLoadView()
@property (strong,nonatomic) UILabel *showLabel;
@end
@implementation DefaultTopLoadView
-(instancetype)initWithFrame:(CGRect)frame{
    self=[super initWithFrame:frame];
    if(self){
        self.showLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 40, 320, 10)];
        [self.showLabel setText:@"test"];
        [self addSubview:self.showLabel];
//        [self addObserver:self forKeyPath:@"topRefreshStatus" options:NSKeyValueObservingOptionNew context:nil];
//        [self addObserver:self forKeyPath:@"topRefreshStatus" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}
-(void)adjustStatusByTop:(float) y{
    NSLog(@"%f----%f",y,self.frame.size.height);
    if(self.parentScrollView.isDragging){
        if(y<=self.frame.origin.y){
            self.topRefreshStatus = REFRESH_STATUS_BEFORE_REFRESH;
        }else{
            self.topRefreshStatus = REFRESH_STATUS_NORMAL;
        }
    }else{
        if(y<=self.frame.origin.y){
            self.topRefreshStatus = REFRESH_STATUS_REFRESHING;
        }
        
    }
}
-(void)setTopRefreshStatus:(int)topRefreshStatus{
    if(_topRefreshStatus == topRefreshStatus){
        return;
    }
    switch (topRefreshStatus) {
        case REFRESH_STATUS_NORMAL:{
            [UIView animateWithDuration:0.25 animations:^{
                self.parentScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
                 self.parentScrollView.scrollEnabled = YES;
                
            }];

           
            [self showNormal];
            break;
        }
        case REFRESH_STATUS_BEFORE_REFRESH:
            [self showBeforeRefresh];
            break;
        case REFRESH_STATUS_REFRESHING:
        {
            [UIView animateWithDuration:0.25 animations:^{
               self.parentScrollView.contentInset = UIEdgeInsetsMake(self.frame.size.height, 0, 0, 0);
                self.parentScrollView.scrollEnabled = NO;

            }];
            
            [self showRefreshing];
            [self.actionTar performSelector:self.action withObject:nil]; 
            break;
        }
            
        default:
            break;
    }
    _topRefreshStatus = topRefreshStatus;

}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if([keyPath isEqualToString:@"topRefreshStatus"]){
        //        NSLog(@"%@",change);
        NSNumber *statusNum = (NSNumber *)[change objectForKey:@"new"];
            }
    //NSLog(@"%@,%@,%@,%@",keyPath,object,change,context);
}

-(void) showBeforeRefresh{
    [self.showLabel setText:@"松开刷新"];
}
-(void) showNormal{
    [self.showLabel setText:@"下拉刷新"];
}
-(void) showRefreshing{
    [self.showLabel setText:@"刷新中..."];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

@end

可能还有很多缺陷 不过我也是看看这个的实现来学点东西。

尝试这弄这个 也学到了一些东西;

首先就是 kvo 以前从来没有使用过。甚至不知道这个东西。 用起来才知道 真的很不错。 不过我的代码应该忘了取消监听了。 不改了。实际开发中一定要记得。

然后就是 objc_setAssociatedObject 很强大的功能。相信用的地方不会太多。不过有时候用它有奇效。

最后就是对之前了解的 UIEdgeInsetsMake 了解的更深刻了。

这个例子就到这里吧。感觉在写下去 也就是时间的问题了。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值