您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)iOS如何自定義可展示、交互的scrollView滾動(dòng)條,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
首先看一下效果圖:
簡(jiǎn)單闡述一下實(shí)現(xiàn)邏輯:自定義滾動(dòng)條視圖繼承UIView,添加滾動(dòng)條滑動(dòng)事件、其他區(qū)域點(diǎn)擊事件,通過代理方法與列表關(guān)聯(lián)。在列表刷新完成及scrollView代理方法中更新滾動(dòng)條。
簡(jiǎn)單說一下計(jì)算邏輯,如上圖(原諒博主的圖)所示,其中b、c、d是已知的。首先計(jì)算滾動(dòng)條的高度a,理想情況下它與整個(gè)滾動(dòng)區(qū)域b的比值應(yīng)該等于scrollView的展示區(qū)域b與scrollView的內(nèi)容高度d的比值,就是 a/b = b/d,即 a = b*b/d,也是就代碼中的“_scrollBar.barHeight = pow(tableView.bounds.size.height,2) / tableView.contentSize.height;”這句話。
既然是理想情況,就有特殊情況,首先如果內(nèi)容高度d小于展示區(qū)域b,就是說不需要滑動(dòng)時(shí),這里可以有兩種處理,第一種是隱藏滾動(dòng)條,第二種是將滾動(dòng)條高度設(shè)為與滾動(dòng)區(qū)域一致,方便觀察,這里使用后一種。還有一種特殊情況就是,如果內(nèi)容區(qū)域d無限增大,則滾動(dòng)條高度a無限減小,所以需要給定一個(gè)最小高度限制。
好了,上面計(jì)算出滾動(dòng)條高度a,然后計(jì)算滾動(dòng)條Y向位置x,很容易看出來 x/b = c/d,正常情況下這是沒有問題的,但是當(dāng)滾動(dòng)條高度非常小,小于我們?cè)O(shè)定的最小高度時(shí)就會(huì)有誤差,那么換另一種寫法 x/(b-a) = c/(d-b),即 x = (b-a)*c/(d-b),代碼中“_scrollBar.yPosition = (_scrollBar.bounds.size.height - _scrollBar.barHeight) *_tableView.contentOffset.y / (_tableView.contentSize.height -_scrollBar.bounds.size.height);”這句話。那么在scrollView代理方法中更新這兩項(xiàng)就實(shí)現(xiàn)了滾動(dòng)條高度根據(jù)scrollView內(nèi)容增減,并根據(jù)scrollView滑動(dòng)而移動(dòng)。
最后在我們自定義滾動(dòng)條的代理方法中設(shè)置scrollView的contentOffset,即可實(shí)現(xiàn)scrollView隨著滾動(dòng)條的點(diǎn)擊滑動(dòng)而移動(dòng)。計(jì)算方法與上面一致 x/(b-a) = c/(d-b),區(qū)別是這次動(dòng)條Y向位置x是已知的,scrollView的Y向偏移量c是未知的,即 c = (d-b)*x/(b-a),代碼中“[_tableViewsetContentOffset:CGPointMake(0, (_tableView.contentSize.height -_scrollBar.bounds.size.height) * scrollBar.yPosition / (_scrollBar.bounds.size.height - _scrollBar.barHeight))];”這句話。
下面貼上相關(guān)代碼:
控制器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]; //創(chuàng)建控件 [self creatControl]; //添加頭部刷新 [self addHeaderRefresh]; //添加尾部刷新 [self addFooterRefresh]; } - (void)getInfo { NSArray *array = @[@"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"http://blog.csdn.net/hero_wqb", @"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"http://blog.csdn.net/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(@"已經(jīng)刷新好了"); }); } - (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]; //滾動(dòng)展示條 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; //滾動(dòng)條 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 self.array.count; } - (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]; } cell.textLabel.text = [_array[indexPath.row] stringByAppendingString:[NSString stringWithFormat:@"_%ld", indexPath.row]]; 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(), ^{ //更新滾動(dòng)條高度 if (tableView.contentSize.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) / tableView.contentSize.height; _tableBar.barHeight = pow(tableView.bounds.size.height, 2) / tableView.contentSize.height; } //更新滾動(dòng)條Y向位置 _scrollBar.yPosition = (_scrollBar.bounds.size.height - _scrollBar.barHeight) * _tableView.contentOffset.y / (_tableView.contentSize.height - _scrollBar.bounds.size.height); _tableBar.yPosition = (_tableBar.bounds.size.height - _tableBar.barHeight) * _tableView.contentOffset.y / (_tableView.contentSize.height - _tableBar.bounds.size.height); }); } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { //滑動(dòng)到底部自動(dòng)刷新 if (_tableView.contentSize.height > _tableView.frame.size.height && _tableView.contentOffset.y + _tableView.frame.size.height > _tableView.contentSize.height - 40 && _page < 50) { [_tableView footerBeginRefreshing]; } //更新滾動(dòng)條位置 _scrollBar.yPosition = (_scrollBar.bounds.size.height - _scrollBar.barHeight) * scrollView.contentOffset.y / (scrollView.contentSize.height - _scrollBar.bounds.size.height); _tableBar.yPosition = (_tableBar.bounds.size.height - _tableBar.barHeight) * scrollView.contentOffset.y / (scrollView.contentSize.height - _tableBar.bounds.size.height); } #pragma mark - SXScrollBarDelegate - (void)scrollBarDidScroll:(HWScrollBar *)scrollBar { [_tableView setContentOffset:CGPointMake(0, (_tableView.contentSize.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, (_tableView.contentSize.height - _scrollBar.bounds.size.height) * scrollBar.yPosition / (_scrollBar.bounds.size.height - _scrollBar.barHeight))]; }]; } @end
自定義滾動(dòng)條HWScrollBar:
#import <UIKit/UIKit.h> @class HWScrollBar; @protocol HWScrollBarDelegate <NSObject> //滾動(dòng)條滑動(dòng)代理事件 - (void)scrollBarDidScroll:(HWScrollBar *)scrollBar; //滾動(dòng)條點(diǎn)擊代理事件 - (void)scrollBarTouchAction:(HWScrollBar *)scrollBar; @end @interface HWScrollBar : UIView //背景色 @property (nonatomic, strong) UIColor *backColor; //前景色 @property (nonatomic, strong) UIColor *foreColor; //滾動(dòng)動(dòng)畫時(shí)長(zhǎng) @property (nonatomic, assign) CGFloat barMoveDuration; //限制滾動(dòng)條最小高度 @property (nonatomic, assign) CGFloat minBarHeight; //滾動(dòng)條實(shí)際高度 @property (nonatomic, assign) CGFloat barHeight; //滾動(dòng)條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]) { //初始化設(shè)置 [self initInfo]; //創(chuàng)建控件 [self creatControl]; //添加手勢(shì) [self addSwipeGesture]; } return self; } - (void)initInfo { _minBarHeight = 40.0f; _barMoveDuration = 0.25f; _foreColor = [UIColor colorWithHexString:@"#2f9cd4"]; _backColor = [UIColor colorWithHexString:@"#e6e6e6"]; self.layer.cornerRadius = 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; //滾動(dòng)條 UIView *scrollBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)]; scrollBar.backgroundColor = _foreColor; scrollBar.layer.cornerRadius = self.bounds.size.width * 0.5; scrollBar.layer.masksToBounds = YES; [self addSubview:scrollBar]; _scrollBar = scrollBar; } - (void)addSwipeGesture { //添加點(diǎn)擊手勢(shì) UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; [_backView addGestureRecognizer:tap]; //添加滾動(dòng)條滑動(dòng)手勢(shì) 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; temFrame.origin.y = yPosition; _scrollBar.frame = temFrame; } - (void)handlePan:(UIPanGestureRecognizer *)sender { //獲取偏移量 CGFloat moveY = [sender translationInView:self].y; //重置偏移量,避免下次獲取到的是原基礎(chǔ)的增量 [sender setTranslation:CGPointMake(0, 0) inView:self]; //在頂部上滑或底部下滑直接返回 if ((_yPosition <= 0 && moveY <= 0) || (_yPosition >= self.bounds.size.height - _barHeight && moveY >= 0)) return; //賦值 self.yPosition += moveY; //防止瞬間大偏移量滑動(dòng)影響顯示效果 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 { //點(diǎn)擊滾動(dòng)條返回 if (sender.view == _scrollBar) return; //獲取點(diǎn)擊的位置 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
關(guān)于“iOS如何自定義可展示、交互的scrollView滾動(dòng)條”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。