JHPullToRefreshKit 1.0.1

JHPullToRefreshKit 1.0.1

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最新发布2015年3月

Jeff Hurray维护。



  • 作者:
  • Jeff Hurray

一个抽象基类,易于创建自定义下拉刷新控件

上述所有内容都使用了不到150行代码。

为什么还需要另一个下拉刷新库?

现在有很多PTR库,但没有一个完全适合我的需求。下拉刷新控件完成时很棒,但制作起来很繁琐。我创建这个库,这样我就可以直接跳入自定义动画,而不必担心自定义。对于我的实现,你只需要重写一些抽象方法,详细说明高度、动画持续时间和每个动画周期中运行的内容。

我的实现提供了以下功能:

添加到UIScrollView

在初始化后,您只需一行代码即可将刷新控件添加到滚动视图。当滚动视图被下拉超过其高度时,将调用刷新块中的代码。

重要:您必须调用endRefreshing来停止刷新控件。一个很好的地方是在网络请求的回调中做这件事。

-(void) viewDidLoad {
    [super viewDidLoad];
    ...
    self.myRefreshControl = [[MyRefreshControl alloc] init];
    [self.myRefreshControl addToScrollView:self.tableView withRefreshBlock:^{
         [self tableViewWasPulledToRefresh];
    }];
    ...
}

-(void)tableViewWasPulledToRefresh {
    [self someBigNetworkRequestWithCallback:^{
        [self.myRefreshControl endRefreshing];
    }];
}

JHRefreshControl的子类化

JHRefreshControl是一个抽象基类,这意味着您需要覆盖一些函数。以下方法必须实现,否则您的应用程序会崩溃。您可以在AbstractFunctionsCopyandPaste.txt中找到一个代码片段,包含.m文件中所有方法的代码,可以直接复制和粘贴。

ColorChangeRefreshControl.m中可以找到一个很好的例子。

抽象类方法

// sets the height of the refresh control  
+(CGFloat)height;

//sets the animation duration of each animation cycle for the refresh control.
+(NSTimeInterval)animationDuration;

抽象类实例方法

// use this to setup the refresh control.
// put setup code here instead of init
-(void)setup;

// Used to control UI elements during scrolling
// only called while scroll view is scrolling
// not during PTR animation
-(void)handleScrollingOnAnimationView:(UIView *)animationView
                     withPullDistance:(CGFloat)pullDistance
                        pullRatio:(CGFloat)pullRatio
                         pullVelocity:(CGFloat)pullVelocity;
  • pullDistance:滚动视图的偏移量
  • pullRatio:偏移量与刷新控件高度的比率
  • pullVelocity: 滚动视图被拉动的速度
// Set refresh animation to correct state before a new cycle begins
// Called before each animation
-(void)setupRefreshControlForAnimationView:(UIView *)animationView;

// UI changes to be animated continuously 
// until endRefreshing is called. 
-(void)animationCycleForAnimationView:(UIView *)animationView;

其他有用的属性和方法

// manual refresh
// call in view controller
-(void)forceRefresh;

// called to end the animation
// call in view controller
-(void)endRefreshing;

// should reset UI elements here
// called after refresh control finishes and is hidden
// override in subclass
-(void)resetAnimationView:(UIView *)animationView;

// called to add a subview to the animation view
// important to only add subviews in this manner
// call in subclass to setup refresh control
-(void)addSubviewToRefreshAnimationView:(UIView *)subview;

// sets the animation delay
// override in subclass
+(NSTimeInterval)animationDelay;

//getters
@property (atomic, readonly, getter=isRefreshing) BOOL refreshing;
@property (nonatomic, readonly) CGFloat height;
@property (nonatomic, readonly) NSTimeInterval animationDuration;
@property (nonatomic, readonly) NSTimeInterval animationDelay;

内部原理

你说的这个“动画周期”是什么意思??

动画周期是在动画块内部重复执行的UI代码。现实生活中的例子包括Yik Yak应用中 yak 头部的一次旋转,或者在Snapchat应用中一次颜色的改变。

那么真正发生了什么??

刷新控制有一个运行动画的子视图。当刷新控制被拉动时,它会为周期设置动画视图(确保yak的头部处于正确的起始角度),然后执行动画(yak的头部旋转一次。)然后检查是否调用了 endRefreshing。如果已经调用,就退出。如果没有调用,则再次设置并运行动画(并继续这种模式,直到调用 endRefreshing)。

以下过程会在从拉动滚动视图刷新到调用 endRefreshing 期间持续运行。

 setupRefreshControlForAnimation
 -> animate [ animation cycle ]
    -> completion [animation cycle finished]
        -> if refreshing:
            recurse (another cycle)
        -> else:
            refreshing ended 
            -> [completion animation] 
            -> reset animation view

调试

如果您想调试上述过程,请将 JHPTR_DEBUG_FLAG 设置为 YESJHPullToRefreshKit.h 中。这将提供详细输出,您可以使用这些信息查看在使用 JHRefreshControlJHLayerAnimationRefreshControl 子类时调用哪些函数。

自定义

变量

JHRefreshControlType

这是在滚动视图向下滚动时(偏移量 < 高度)刷新控制显示的方式。必须在 initWithType: 中设置。如果调用简单 init,则默认为 SlideDown

  • JHRefreshControlTypeSlideDown: 刷新控制将随着滚动视图的滚动而向下滑动。

  • JHRefreshControlTypeBackground: 刷新控制位于滚动视图后面,并且在滚动视图向下滚动时被揭露。

MyRefreshControl *refreshControl = [[MyRefreshControl alloc] initWithType:JHRefreshControlTypeSlideDown];

JHRefreshControlAnchorPosition

这是在滚动视图已经滚动超过其高度时动画视图的锚定方式。(偏移量 > 高度)。默认为 Top

  • JHRefreshControlAnchorPositionTop: 动画视图将固定在顶部。

  • JHRefreshControlAnchorPositionMiddle: 动画视图将随着滚动视图偏移量的增加而拉伸,并固定在中间。

  • JHRefreshControlAnchorPositionBottom: 动画视图将固定在底部。

self.anchorPosition = JHRefreshControlAnchorPositionTop;

JHRefreshControlAnimationType

这决定了动画周期在哪种类型的动画块中运行。

  • JHRefreshControlAnimationTypeDefault: 动画周期在正常的 [UIView animationWithDuration:...] 块内部运行。
  • JHRefreshControlAnimationTypeKeyFrame: 动画周期在 [UIView animateKeyframesWithDuration:...] 块内部运行。这意味着您应该在您的 animationCycleForRefreshView: 函数内部调用 [UIView addKeyframeAnimationWithRelativeStartTime:...]。
  • JHRefreshControlAnimationTypeSpring: 动画周期在 [[UIView animateWithDuration: delay: usingSpringWithDamping: initialSpringVelocity:...] 块内部运行。
self.animationType = JHRefreshControlAnimationTypeDefault;

您还可以为这些动画添加 UIViewAnimationOptions

self->animationOptions = UIViewAnimationOptionCurveEaseInOut;

退出动画

要添加例如我提供的 Yahoo 新闻摘要示例中的退出动画,请覆盖以下函数。退出动画在调用 endRefreshing 后以及注销刷新控件之前调用。完成时一定要调用 completion(),以便刷新控件知道要注销!

-(void)exitAnimationForRefreshView:(UIView *)animationView withCompletion:(JHCompletionBlock)completion;

以下是 淡出至黑色 退出动画的示例

-(void) exitAnimationForRefreshView:(UIView *)animationView withCompletion:(JHCompletionBlock)completion {
    [UIView animateWithDuration:1.0 animations:^{
        self.backgroundColor = [UIColor blackColor];
        self.mySubview.alpha = 0.0;
    } completion:^(BOOL finished) {
        [self.mySubview removeFromSuperview];
        completion();
    }];
}

CALayer 动画

有些动画 лучше выполнять с помощью CABasicAnimations。这一点的一个很好的例子是旋转 ≥ 360 度。如果你想让一个视图旋转 450 度,UIView 动画块只能让它旋转 90 度。如果你想有一个执行 CABasicAnimations 的刷新控件,就必须继承 JHLayerAnimationRefreshControl 并覆盖另一個抽象方法。

-(CALayer *) targetLayer; 设置你想要动画的层。

要向这个层添加动画,只需调用
-(void)addCABasicAnimationWithKeyPath:(NSString *)keyPath fromValue:(CGFloat)fromValue toValue:(CGFloat)toValue;

我提供的 Yahoo 新闻摘要示例就是一个很好的例子。为了使点旋转,我在 setup 中调用上述函数。

[self addCABasicAnimationWithKeyPath:@"transform.rotation.z" fromValue:0.0 toValue:2*M_PI];

这确保了我在 targetLayer 中返回的层将在每个动画周期旋转 360 度。

请注意,当继承 JHLayerAnimationRefreshControl 时,setupRefreshControlForAnimationView:animationCycleForAnimationView: 不需要被覆盖。然而,如果你想要执行其他 UIView 动画,你可以覆盖这些函数。

代理

你的视图控制器或滚动视图可以符合一些代理方法。

self.myRefreshControl.delegate = self;
@protocol JHRefreshControlDelegate <NSObject>

-(void)refreshControlDidStart:(JHRefreshControl *)refreshControl;
-(void)refreshControlDidEnd:(JHRefreshControl *)refreshControl;

@optional
-(void)refreshControlDidStartAnimationCycle:(JHRefreshControl *)refreshControl;
-(void)refreshControlDidEndAnimationCycle:(JHRefreshControl *)refreshControl;

@end

联系信息 && 贡献

请随时通过电子邮件发给我 [email protected]。我很乐意听听你的看法,或者看到使用此技术的示例。

MIT 许可证