IOS 类似抖音下拉刷新与自定义上拉加载
IOS 类似抖音下拉刷新与自定义上拉加载
最近UICollectionView中使用了pageEnabled,MJRresh直接使用时出现偏移。这里就暂时考虑简单的做法。
首先考虑在UICollection与拖动手势之间的问题。
解决UICollectionView上添加手势不能触发。
这里使用了子类继承UICollectionView
#import "INMyCollectionView.h"@implementation INMyCollectionView-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[[self nextResponder] touchesBegan:touches withEvent:event];[super touchesBegan:touches withEvent:event];
}-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {[[self nextResponder] touchesMoved:touches withEvent:event];[super touchesMoved:touches withEvent:event];
}- (void)touchesEnded:(NSSet *)toucheswithEvent:(UIEvent *)event {[[self nextResponder] touchesEnded:touches withEvent:event];[super touchesEnded:touches withEvent:event];
}@end
在View上添加拖动手势
self.startPoint = CGPointZero;
self.isInLoading = NO;
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureHandle:)];
panGesture.minimumNumberOfTouches = 1;
panGesture.maximumNumberOfTouches = 1;
panGesture.delegate = self;
[self addGestureRecognizer:panGesture];
处理手势判断
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {return YES;
}
// 给加的手势设置代理, 并实现此协议方法
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;CGPoint pos = [pan velocityInView:pan.view];if (pos.y > 0) {return YES;}}return NO;
}
在处理拖动手势
(void)panGestureHandle:(UIPanGestureRecognizer *)pan{if (self.collectionView.contentOffset.y > 0) {return;}DebugLog(@"panGestureHandle");if (self.isInLoading) {return;}if (pan.state == UIGestureRecognizerStateBegan) {DebugLog(@"UIGestureRecognizerStateBegan");self.startPoint = [pan translationInView:self];self.collectionView.scrollEnabled = NO;} if (pan.state == UIGestureRecognizerStateChanged) {DebugLog(@"UIGestureRecognizerStateChanged");CGPoint point = [pan translationInView:self];CGFloat distance = point.y - self.startPoint.y;if (distance > 0) {self.refreshStateLabel.text = @"下拉刷新";CGFloat scale = distance/KMaxScrollRefreshHeight;if (scale > 1.0) {scale = 1.0;}self.refreshStateLabel.alpha = scale;self.navbarView.alpha = (1-scale);self.refreshStateLabel.frame = CGRectMake(0.0, scale*(kStatusBarHeight + [BaseView baseSafeAreaEdgeInsets].top) + 5.0, CGRectGetWidth(self.bounds), 44.0);if (distance > KMaxScrollRefreshHeight) {DebugLog(@"可以下拉刷新");}} else {DebugLog(@"上拉操作");self.refreshStateLabel.alpha = 0.0;}} else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled || pan.state == UIGestureRecognizerStateFailed) {DebugLog(@"UIGestureRecognizerStateEnded");self.collectionView.scrollEnabled = YES;CGPoint point = [pan translationInView:self];CGFloat distance = point.y - self.startPoint.y;self.refreshStateLabel.text = @"";if (distance > 0) {if (distance > KMaxScrollRefreshHeight) {DebugLog(@"加载中...");self.refreshStateLabel.text = @"加载中...";self.refreshStateLabel.alpha = 1.0;self.isInLoading = YES;if (self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(refreshLoadingData)]) {[self.actionDelegate refreshLoadingData];}}}}
}当然,类似抖音的下拉,在ScrollDidScoll处理了下
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {if (scrollView.contentOffset.y < 0) {[scrollView setContentOffset:CGPointMake(0.0, 0.0)];} else {// 向上拖动,向上拖动的指定位置后加载更多数据DebugLog(@"向上拖动,向上拖动的指定位置后加载更多数据");}
}
第二部分
自己处理上拉加载更多,这里代码如下
INUpwardRefreshView.h
@protocol INUpwardRefreshViewDelegate;@interface INUpwardRefreshView : BaseView@property (nonatomic, weak) id<INUpwardRefreshViewDelegate>delegate;
@property (nonatomic, strong) UIScrollView *scrollView;- (instancetype)initWithTarget:(UIScrollView *)scrollView;- (void)endRefreshing;@end@protocol INUpwardRefreshViewDelegate <NSObject>- (void)pullUpwardRefreshDidFinish;@end
INUpwardRefreshView.m
//
// INUpwardRefreshView.m
// Views
//
// Created by ABC on 2019/7/26.
//#import "INUpwardRefreshView.h"
#import "Color.h"
#import "NSString+size.h"NSString *const RefreshUpKeyPathContentOffset = @"contentOffset";
NSString *const RefreshUpKeyPathContentSize = @"contentSize";CGFloat const FooterUpHeight = 80;@interface INUpwardRefreshView ()@property (nonatomic, strong) UIActivityIndicatorView *activityView;
@property (nonatomic, strong) UIImageView *arrowView;
@property (nonatomic, strong) UILabel *stateLable;
@property (nonatomic, assign) BOOL isRefresh;
@property (nonatomic, assign) CGFloat lastOffSet;@end@implementation INUpwardRefreshView- (instancetype)initWithTarget:(UIScrollView *)scrollView {self = [super init];if (self) {self.backgroundColor = [UIColor clearColor];_scrollView = scrollView;self.frame = CGRectMake(0, 0, 0, FooterUpHeight);[_scrollView addSubview:self];[self addObserver];}return self;}- (void)layoutSubviews{[super layoutSubviews];CGSize statelabelSize = [self.stateLable.text sizeWithFont:self.stateLable.font forMaxSize:CGSizeMake(MAXFLOAT, 40)];self.stateLable.frame = CGRectMake((CGRectGetWidth(self.bounds) - statelabelSize.width)/2 + 10.0, 0.0, statelabelSize.width, 40);self.arrowView.frame = CGRectMake(CGRectGetMinX(self.stateLable.frame) - CGRectGetWidth(self.arrowView.frame) - 10.0, 0.0, CGRectGetWidth(self.arrowView.frame), 40);self.activityView.frame = CGRectMake(CGRectGetMinX(self.stateLable.frame) - CGRectGetWidth(self.arrowView.frame) - 10.0, (40.0 - 20.0)/2, 20, 20);
}- (void)setCurrentFrame {[self setFrame:CGRectMake(0, MAX(self.scrollView.contentSize.height, CGRectGetHeight(self.scrollView.frame)), self.scrollView.size.width, FooterUpHeight)];[self setNeedsLayout];
}- (void)setFrameHeight:(CGFloat)height {[self setFrame:CGRectMake(0, MAX(self.scrollView.contentSize.height, CGRectGetHeight(self.scrollView.frame)), self.scrollView.size.width, height)];DebugLog(@"frameHeight:%f",height);
}#pragma mark setter
- (UIActivityIndicatorView *)activityView{if (!_activityView) {_activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];_activityView.hidesWhenStopped = YES;[self addSubview:_activityView];}return _activityView;
}- (UIImageView *)arrowView{if (!_arrowView) {_arrowView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 15, 40)];_arrowView.image = [UIImage imageNamed:@"refresh_up_arrow"];//[self addSubview:_arrowView];}return _arrowView;
}- (UILabel *)stateLable{if (!_stateLable) {_stateLable = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 90, 40)];_stateLable.backgroundColor = [UIColor clearColor];_stateLable.font = [UIFont systemFontOfSize:12];_stateLable.textAlignment = NSTextAlignmentLeft;_stateLable.textColor = [UIColor whiteColor];[self addSubview:_stateLable];}return _stateLable;
}#pragma mark private
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change{_stateLable.hidden = NO;CGFloat yOffSet = _scrollView.contentOffset.y;DebugLog(@"yOffSet:%f",yOffSet);CGFloat contentSizeHeight = _scrollView.contentSize.height;CGFloat frameHeight = CGRectGetHeight(_scrollView.frame);if (contentSizeHeight > 0 && contentSizeHeight < frameHeight) {CGFloat insetTop = frameHeight - contentSizeHeight;if (yOffSet+insetTop > 0.0) {//正在拖拽中if (self.scrollView.isDragging) {[UIView animateWithDuration:0.3 animations:^{self.arrowView.hidden = NO;if (yOffSet+insetTop > 100.0) {self.arrowView.transform = CGAffineTransformMakeRotation(M_PI);self.stateLable.text = @"松开夹子";}else{self.arrowView.transform = CGAffineTransformMakeRotation(M_PI*2);self.stateLable.text = @"继续滑动";}}];[self setFrameHeight:(yOffSet+insetTop)];} else {if (yOffSet+insetTop > 100.0) {[self beginRefreshing];}}}} else {//正在拖拽中CGFloat aYBottom = yOffSet - (contentSizeHeight - frameHeight);if (self.scrollView.isDragging) {[UIView animateWithDuration:0.3 animations:^{self.arrowView.hidden = NO;if (aYBottom > 100.0) {self.arrowView.transform = CGAffineTransformMakeRotation(M_PI);self.stateLable.text = @"松开加载";}else{self.arrowView.transform = CGAffineTransformMakeRotation(M_PI*2);self.stateLable.text = @"继续滑动";}}];[self setFrameHeight:yOffSet];} else {if (contentSizeHeight > 0 && aYBottom > 100.0) {[self beginRefreshing];}}}
}#pragma mark publick
- (void)beginRefreshing{[self setFrameHeight:FooterUpHeight];if (!_isRefresh) {_isRefresh = YES;CGFloat insetTop = _scrollView.contentInset.top;//设置偏移量,衔接加载的更多数据[UIView animateWithDuration:0.35 animations:^{//[self.scrollView setContentInset:UIEdgeInsetsMake(insetTop, 0, FooterUpHeight, 0)];[self.activityView startAnimating];self.arrowView.hidden = YES;self.stateLable.text = @"加载中";} completion:^(BOOL finished) {[self startBeginRefresh];}];}
}- (void)startBeginRefresh {// Refresh action!if ([self.delegate respondsToSelector:@selector(pullUpwardRefreshDidFinish)]) {[self.delegate performSelector:@selector(pullUpwardRefreshDidFinish) withObject:nil];}
}- (void)endRefreshing {_isRefresh = NO;[UIView animateWithDuration:0.3 animations:^{[self.activityView stopAnimating];self.arrowView.hidden = YES;self.arrowView.transform = CGAffineTransformMakeRotation(M_PI*2);}];
}#pragma mark KVO
- (void)addObserver{NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;[_scrollView addObserver:self forKeyPath:RefreshUpKeyPathContentOffset options:options context:nil];[_scrollView addObserver:self forKeyPath:RefreshUpKeyPathContentSize options:options context:nil];
}- (void)removeObserver{[_scrollView removeObserver:self forKeyPath:RefreshUpKeyPathContentOffset];[_scrollView removeObserver:self forKeyPath:RefreshUpKeyPathContentSize];
}- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{if ([keyPath isEqualToString:RefreshUpKeyPathContentOffset]) {[self scrollViewContentOffsetDidChange:change];} else if ([keyPath isEqualToString:RefreshUpKeyPathContentSize]) {[self setCurrentFrame];} else {[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];}
}- (void)dealloc{[self removeObserver];
}@end
使用上拉加载的shih
在collection创建的时候,设置下即可
_upwardRefreshView = [[INUpwardRefreshView alloc] initWithTarget:_collectionView];_upwardRefreshView.delegate = self;
源码地址:
https://github.com/goodbruce/DouyinRefresh
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
