iOS⾃定义可展⽰、交互的scrollView滚动条
上⼀篇简述了封装,本篇在此基础上添加了⼀个⾃定义的scrollView滚动条,可展⽰、交互,⾸先看⼀下效果图:
简单阐述⼀下实现逻辑:⾃定义滚动条视图继承UIView,添加滚动条滑动事件、其他区域点击事件,通过代理⽅法与列表关联。在列表刷新完成及scrollView代理⽅法中更新滚动条。
简单说⼀下计算逻辑,如上图(原谅博主的图)所⽰,其中b、c、d是已知的。⾸先计算滚动条的⾼度a,理想情况下它与整个滚动区域b的⽐值应该等于scrollView的展⽰区域b与scrollView的内容⾼度d
的⽐值,就是 a/b = b/d,即 a = b*b/d,也是就代码中的“_scrollBar.barHeight = pow(tableView.bounds.size.height,2) / tSize.height;”这句话。
既然是理想情况,就有特殊情况,⾸先如果内容⾼度d⼩于展⽰区域b,就是说不需要滑动时,这⾥可以有两种处理,第⼀种是隐藏滚动条,第⼆种是将滚动条⾼度设为与滚动区域⼀致,⽅便观察,这⾥
使⽤后⼀种。还有⼀种特殊情况就是,如果内容区域d⽆限增⼤,则滚动条⾼度a⽆限减⼩,所以需要给定⼀个最⼩⾼度限制。
好了,上⾯计算出滚动条⾼度a,然后计算滚动条Y向位置x,很容易看出来 x/b = c/d,正常情况下这是没有问题的,但是当滚动条⾼度⾮常⼩,⼩于我们设定的最⼩⾼度时就会有误差,那么换另⼀种写
法 x/(b-a) = c/(d-b),即 x = (b-a)*c/(d-b),代码中“_scrollBar.yPosition = (_scrollBar.bounds.size.height - _scrollBar.barHeight) *_tOffset.y / (_tSize.height -
_scrollBar.bounds.size.height);”这句话。那么在scrollView代理⽅法中更新这两项就实现了滚动条⾼度根据scrollView内容增减,并根据scrollView滑动⽽移动。
最后在我们⾃定义滚动条的代理⽅法中设置scrollView的contentOffset,即可实现scrollView随着滚动条的点击滑动⽽移动。计算⽅法与上⾯⼀致 x/(b-a) = c/(d-b),区别是这次动条Y向位置x是已知
的,scrollView的Y向偏移量c是未知的,即 c = (d-b)*x/(b-a),代码中“[_tableViewsetContentOffset:CGPointMake(0, (_tSize.height -_scrollBar.bounds.size.height) * scrollBar.yPosition /
(_scrollBar.bounds.size.height - _scrollBar.barHeight))];”这句话。
下⾯贴上相关代码:
控制器ViewController:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
/*** ---------------分割线--------------- ***/
#import "ViewController.h"
#import "HWRefresh.h"
#import "HWScrollBar.h"
@interface ViewController ()<UITableViewDataSource, UITableViewDelegate, HWScrollBarDelegate>
@property (nonatomic, strong) NSMutableArray *array;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, weak) HWScrollBar *scrollBar;
@property (nonatomic, weak) HWScrollBar *tableBar;
@property (nonatomic, assign) NSInteger page;
@end
@implementation ViewController
- (NSMutableArray *)array
{
if (!_array) {
_array = [NSMutableArray array];
}
return _array;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
self.page = 1;
//模拟获取信息
[self getInfo];
//创建控件
[self creatControl];
//添加头部刷新
[self addHeaderRefresh];
//添加尾部刷新
[self addFooterRefresh];
}
- (void)getInfo
{
NSArray *array = @[@"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"blog.csdn/hero_wqb", @"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"blog.csdn/hero_wqb"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.page == 1) {
self.array = [NSMutableArray arrayWithArray:array];
}else{
[self.array addObjectsFromArray:array];
}
[_tableView reloadData];
[_tableView headerEndRefreshing];
[_tableView footerEndRefreshing];
NSLog(@"已经刷新好了");
});
}
- (void)creatControl
{
//列表视图
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(20, 64, [[UIScreen mainScreen] bounds].size.width - 100, [[UIScreen mainScreen] bounds].size.height - 164) style:UITableViewStylePlain]; _tableView.dataSource = self;
_tableView.delegate = self;
[self.view addSubview:_tableView];
//滚动展⽰条
HWScrollBar *tableBar = [[HWScrollBar alloc] initWithFrame:CGRectMake(CGRectGetMaxX(_tableView.frame), CGRectGetMinY(_tableView.frame), 5, _tableView.bounds.size.height)];
tableBar.foreColor = [UIColor greenColor];
tableBar.backColor = [UIColor grayColor];
tableBar.userInteractionEnabled = NO;
[self.view addSubview:tableBar];
_tableBar = tableBar;
//滚动条
HWScrollBar *scrollBar = [[HWScrollBar alloc] initWithFrame:CGRectMake(CGRectGetMaxX(_tableView.frame) + 20, CGRectGetMinY(_tableView.frame), 40, _tableView.bounds.size.height)];
scrollBar.delegate = self;
scrollBar.minBarHeight = 80;
[self.view addSubview:scrollBar];
_scrollBar = scrollBar;
}
- (void)addHeaderRefresh
{
__weak typeof(self) weakSelf = self;
[_tableView addHeaderRefreshWithCallback:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.page = 1;
[strongSelf getInfo];
}];
}
- (void)addFooterRefresh
{
__weak typeof(self) weakSelf = self;
[_tableView addFooterRefreshWithCallback:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.page ++;
[strongSelf getInfo];
}];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return unt;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"refreshTest";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
< = [_w] stringByAppendingString:[NSString stringWithFormat:@"_%ld", w]];
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//更新滚动条⾼度
if (tSize.height <= tableView.bounds.size.height) {
_scrollBar.barHeight = tableView.bounds.size.height;
_tableBar.barHeight = tableView.bounds.size.height;
}else {
_scrollBar.barHeight = pow(tableView.bounds.size.height, 2) / tSize.height;
_tableBar.barHeight = pow(tableView.bounds.size.height, 2) / tSize.height;
}
//更新滚动条Y向位置
_scrollBar.yPosition = (_scrollBar.bounds.size.height - _scrollBar.barHeight) * _tOffset.y / (_tSize.height - _scrollBar.bounds.size.height);
_tableBar.yPosition = (_tableBar.bounds.size.height - _tableBar.barHeight) * _tOffset.y / (_tSize.height - _tableBar.bounds.size.height);
});
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//滑动到底部⾃动刷新
if (_tSize.height > _tableView.frame.size.height && _tOffset.y + _tableView.frame.size.height > _tSize.height - 40 && _page < 50) {
[_tableView footerBeginRefreshing];
}
//更新滚动条位置
_scrollBar.yPosition = (_scrollBar.bounds.size.height - _scrollBar.barHeight) * tOffset.y / (tSize.height - _scrollBar.bounds.size.height);
_tableBar.yPosition = (_tableBar.bounds.size.height - _tableBar.barHeight) * tOffset.y / (tSize.height - _tableBar.bounds.size.height);
}
#pragma mark - SXScrollBarDelegate
- (void)scrollBarDidScroll:(HWScrollBar *)scrollBar
{
[_tableView setContentOffset:CGPointMake(0, (_tSize.height - _scrollBar.bounds.size.height) * scrollBar.yPosition / (_scrollBar.bounds.size.height - _scrollBar.barHeight))];
}
- (void)scrollBarTouchAction:(HWScrollBar *)scrollBar
{
[UIView animateWithDuration:scrollBar.barMoveDuration animations:^{
[_tableView setContentOffset:CGPointMake(0, (_tSize.height - _scrollBar.bounds.size.height) * scrollBar.yPosition / (_scrollBar.bounds.size.height - _scrollBar.barHeight))];
}];
}
@end
⾃定义滚动条HWScrollBar:
#import <UIKit/UIKit.h>
@class HWScrollBar;
@protocol HWScrollBarDelegate <NSObject>
//滚动条滑动代理事件
- (void)scrollBarDidScroll:(HWScrollBar *)scrollBar;
//滚动条点击代理事件
- (void)scrollBarTouchAction:(HWScrollBar *)scrollBar;
@end
@interface HWScrollBar : UIView
//背景⾊
@property (nonatomic, strong) UIColor *backColor;
//前景⾊
@property (nonatomic, strong) UIColor *foreColor;
//滚动动画时长
@property (nonatomic, assign) CGFloat barMoveDuration;
/
/限制滚动条最⼩⾼度
@property (nonatomic, assign) CGFloat minBarHeight;
//滚动条实际⾼度
@property (nonatomic, assign) CGFloat barHeight;
//滚动条Y向位置
@property (nonatomic, assign) CGFloat yPosition;
//代理
@property (nonatomic, weak) id<HWScrollBarDelegate> delegate;
@end
/*** ---------------分割线--------------- ***/
#import "HWScrollBar.h"
#import "UIColor+HW.h"
@interface HWScrollBar ()
@property (nonatomic, weak) UIView *scrollBar;
@property (nonatomic, weak) UIView *backView;
@end
@implementation HWScrollBar
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
//初始化设置
[self initInfo];
/
/创建控件
[self creatControl];
//添加⼿势
[self addSwipeGesture];
}
return self;
如何设置滚动条的位置}
- (void)initInfo
{
_minBarHeight = 40.0f;
_barMoveDuration = 0.25f;
_foreColor = [UIColor colorWithHexString:@"#2f9cd4"];
_backColor = [UIColor colorWithHexString:@"#e6e6e6"];
Radius = self.bounds.size.width * 0.5;
self.layer.masksToBounds = YES;
self.backgroundColor = _backColor;
}
- (void)creatControl
{
//背景视图
UIView *backView = [[UIView alloc] initWithFrame:self.bounds];
[self addSubview:backView];
_backView = backView;
//滚动条
UIView *scrollBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)]; scrollBar.backgroundColor = _foreColor;
Radius = self.bounds.size.width * 0.5;
scrollBar.layer.masksToBounds = YES;
[self addSubview:scrollBar];
_scrollBar = scrollBar;
}
- (void)addSwipeGesture
{
//添加点击⼿势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; [_backView addGestureRecognizer:tap];
//添加滚动条滑动⼿势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [_scrollBar addGestureRecognizer:pan];
}
- (void)setForeColor:(UIColor *)foreColor
{
_foreColor = foreColor;
_scrollBar.backgroundColor = _foreColor;
}
- (void)setBackColor:(UIColor *)backColor
{
_backColor = backColor;
self.backgroundColor = backColor;
}
- (void)setBarHeight:(CGFloat)barHeight
{
_barHeight = barHeight > _minBarHeight ? barHeight : _minBarHeight;
CGRect temFrame = _scrollBar.frame;
temFrame.size.height = _barHeight;
_scrollBar.frame = temFrame;
}
-
(void)setYPosition:(CGFloat)yPosition
{
_yPosition = yPosition;
CGRect temFrame = _scrollBar.frame;
_scrollBar.frame = temFrame;
}
- (void)handlePan:(UIPanGestureRecognizer *)sender
{
//获取偏移量
CGFloat moveY = [sender translationInView:self].y;
/
/重置偏移量,避免下次获取到的是原基础的增量
[sender setTranslation:CGPointMake(0, 0) inView:self];
//在顶部上滑或底部下滑直接返回
if ((_yPosition <= 0 && moveY <= 0) || (_yPosition >= self.bounds.size.height - _barHeight && moveY >= 0)) return;
//赋值
self.yPosition += moveY;
//防⽌瞬间⼤偏移量滑动影响显⽰效果
if (_yPosition < 0) self.yPosition = 0;
if (_yPosition > self.bounds.size.height - _barHeight && moveY >= 0) self.yPosition = self.bounds.size.height - _barHeight; //代理
if (_delegate && [_delegate respondsToSelector:@selector(scrollBarDidScroll:)]) {
[_delegate scrollBarDidScroll:self];
}
}
- (void)handleTap:(UITapGestureRecognizer *)sender
{
//点击滚动条返回
if (sender.view == _scrollBar) return;
//获取点击的位置
CGFloat positionY = [sender locationInView:self].y;
//赋值
[UIView animateWithDuration:_barMoveDuration animations:^{
self.yPosition = positionY > _yPosition ? positionY - _barHeight : positionY;
}];
//代理
if (_delegate && [_delegate respondsToSelector:@selector(scrollBarTouchAction:)]) {
[_delegate scrollBarTouchAction:self];
}
}
@end
Demo
猜你喜欢:。
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论