iOS 模仿騰訊新聞首頁,指示條及頂部滾動條效果
阿新 • • 發佈:2019-01-28
//
// ViewController.m
// 騰訊新聞模仿
//
// Created by Eva on 2017/7/7.
// Copyright © 2017年 shanghaiWOW. All rights reserved.
//
#import "ViewController.h"
#import "TabViewController.h"
#import "Masonry.h"
#define WIDTH [UIScreen mainScreen].bounds.size.width
#define HEIGHT [UIScreen mainScreen].bounds.size.height
#define randomColor [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1]
@interface ViewController ()<UIScrollViewDelegate>
{
//標識當前頁數
NSInteger _curPage;
NSInteger _selectPage;
//記錄停下時的offset
CGFloat contentOffsetX;
}
@property (nonatomic, strong)UIScrollView *topScroll; //頂部滾動檢視
@property (nonatomic, strong)UIView * indicatorView; //遮罩
@property (weak, nonatomic) IBOutlet UIScrollView *mainScrollView;
@property (nonatomic, strong) NSMutableArray *tagArray;
@property (nonatomic, strong) NSMutableArray *vcArray;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initTopScroll];
[self initBottomController];
}
//佈局頂部滾動檢視
- (void)initTopScroll
{
[self.view addSubview:self.topScroll];
//新增頂部tag的button,並建立對應的VC存入陣列
for (NSInteger i = 0; i < self.tagArray.count; i ++) {
[self addTagBtn:i];
TabViewController *vc = [[TabViewController alloc] init];
vc.index = i;
vc.titleString = _tagArray[i];
[self.vcArray addObject:vc];
}
[self.topScroll addSubview:self.indicatorView];
[_indicatorView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_topScroll).offset(40);
make.left.equalTo(_topScroll).offset(12);
make.height.equalTo(@1);
make.width.equalTo(@31);
}];
}
- (void)initBottomController {
self.mainScrollView.contentSize = CGSizeMake(WIDTH * self.tagArray.count, HEIGHT);
self.mainScrollView.pagingEnabled = YES;
self.mainScrollView.delegate = self;
_curPage = 0;
_selectPage = 0;
//先新增第一個
NSInteger tag = 0;
[self addController:tag];
}
- (void)addTagBtn:(NSInteger)index {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
CGFloat strWidth = [self getWidthWithTitle:WIDTH andFont:15 andStr:_tagArray[index]];
[btn setTitle:_tagArray[index]forState:UIControlStateNormal];
btn.frame = CGRectMake(_topScroll.contentSize.width, 0, strWidth + 25, 50);
btn.titleLabel.font = [UIFont fontWithName:@"PingFangSC-Light" size:15];
[btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_topScroll addSubview:btn];
[btn addTarget:self action:@selector(didClickTopTag:) forControlEvents:UIControlEventTouchUpInside];
btn.tag = 200 + index;
btn.backgroundColor = randomColor;
_topScroll.contentSize = CGSizeMake(CGRectGetMaxX(btn.frame) , 30);
}
- (void)didClickTopTag:(UIButton *)btn {
[self changeToPage:btn.tag - 200];
}
- (void)changeToPage:(NSInteger)toPage {
_selectPage = toPage;
[self addController:toPage];
[self configScrollOffset];
}
//新增檢視
- (void)addController:(NSInteger)tag{
TabViewController *vc = self.vcArray[tag];
vc.view.frame = CGRectMake(WIDTH * tag, 0, WIDTH, HEIGHT);
[self.mainScrollView setContentOffset:CGPointMake(tag *WIDTH, 0) animated:YES];
if ([self.mainScrollView.subviews containsObject:vc.view]) {
return;
}else {
vc.view.backgroundColor = randomColor;
[self.mainScrollView addSubview:vc.view];
}
}
//點選頂部切換滾動位置
- (void)configScrollOffset {
self.mainScrollView.userInteractionEnabled = YES;
CGFloat width = _topScroll.frame.size.width;
//向右移動 後面留出下一個btn+60 的位置
if ( _selectPage > _curPage) {
if ( _selectPage < self.tagArray.count - 1) {
UIButton * nextBtn = [_topScroll viewWithTag:200 + _selectPage + 1];
CGFloat nextPoint = CGRectGetMaxX(nextBtn.frame);
if (nextPoint - width >0) {//當在前面兩頁的時候可能offset會變負值
// && (nextPoint - width > contentOffset || contentOffset - nextPoint + width > width - seleBtn.width)
[UIView animateWithDuration:0.4 animations:^{
[_topScroll setContentOffset:CGPointMake(nextPoint -width, 0)];
}];
}
}
else if (_selectPage == self.tagArray.count - 1){
[UIView animateWithDuration:0.4 animations:^{
[_topScroll setContentOffset: CGPointMake(_topScroll.contentSize.width - width, 0)];
}];
}
}
//向左 前面留出上一個btn的位置
else if ( _selectPage < _curPage) {
if (_selectPage > 0) {
UIButton *lastBtn = [_topScroll viewWithTag:200 + _selectPage -1];
CGFloat lastPoint = CGRectGetMinX(lastBtn.frame);
if (lastPoint < _topScroll.contentSize.width - width ) {//當最後一頁上翻時offset可能超過contentsize
[UIView animateWithDuration:0.4 animations:^{
[_topScroll setContentOffset:CGPointMake(lastPoint , 0)];
}];
}
}
else {
[UIView animateWithDuration:0.4 animations:^{
[_topScroll setContentOffset:CGPointMake(0, 0)];
}];
}
}
}
#pragma mark - ScrollViewDelegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGFloat offsetX = scrollView.contentOffset.x;
NSInteger currentPag = offsetX / WIDTH;
[self changeToPage:currentPag];
_curPage = currentPag;
contentOffsetX = scrollView.contentOffset.x;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(@"**********停止拖拽***********");
}
//非手動觸發時的停止滾動
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{
NSLog(@"**********停止滾動***********");
self.mainScrollView.userInteractionEnabled = YES;
}
//根據滾動的offset調整_indicatorView指示條的位置
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.tag == 500) {return;}
CGFloat contentOffset = scrollView.contentOffset.x;
NSLog(@"當前頁===%f====%td===%td,偏移量相差%f", contentOffset,_curPage,_selectPage,contentOffset - contentOffsetX);
CGFloat width = scrollView.frame.size.width;
NSInteger offIndex = (contentOffset - contentOffsetX)/WIDTH;
if ((contentOffset - contentOffsetX) > 1.0f) { // 向左拖拽
//最後一頁
if (contentOffset > ( _tagArray.count - 1) * WIDTH ) {
return;
}
NSLog(@"=====偏移到第%td頁",offIndex);
NSInteger currentPage = _curPage + offIndex;
UIButton *curBtn = [_topScroll viewWithTag:200 + currentPage];
CGFloat curBtnMinX = CGRectGetMinX(curBtn.frame);
UIButton *nextBtn = [_topScroll viewWithTag:200 + _curPage + offIndex + 1];
CGFloat nextBtnMinX = CGRectGetMinX(nextBtn.frame);
CGFloat space = (nextBtnMinX - curBtnMinX);
CGFloat widthSpace = (nextBtn.frame.size.width- curBtn.frame.size.width);
CGFloat offsetXIndicator = (contentOffset - (_curPage + offIndex)* width)/width * space;
CGFloat offsetWidth = (contentOffset - (_curPage + offIndex) * width)/width * widthSpace;
NSLog(@"x向右的位移 === %f ",offsetXIndicator);
[_indicatorView mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_topScroll.mas_left).offset(curBtnMinX + 13 + offsetXIndicator);
make.width.equalTo(@(curBtn.frame.size.width - 25 + offsetWidth));
}];
}
else if ((contentOffsetX - contentOffset) > 1.0f ) { // 向右拖拽
if (contentOffset < -1 ) {
return;
}
NSLog(@"=====偏移到第%td頁",offIndex);
NSInteger currentPage = _curPage + offIndex;
UIButton *curBtn = [_topScroll viewWithTag:200 + currentPage];
CGFloat curBtnMinX = CGRectGetMinX(curBtn.frame);
UIButton *nextBtn = [_topScroll viewWithTag:200 +_curPage + offIndex - 1];
CGFloat nextBtnMinX = CGRectGetMinX(nextBtn.frame);
CGFloat space = (curBtnMinX - nextBtnMinX);
CGFloat widthSpace = (curBtn.frame.size.width- nextBtn.frame.size.width);
CGFloat offsetXIndicator = (contentOffset - (_curPage + offIndex)* width)/width * space;
CGFloat offsetWidth = (contentOffset - (_curPage + offIndex) * width)/width * widthSpace;
NSLog(@"x向左的位移 === %f ",offsetXIndicator);
[_indicatorView mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_topScroll.mas_left).offset(curBtnMinX+ 13 +offsetXIndicator);
make.width.equalTo(@(curBtn.frame.size.width - 25 + offsetWidth ));
}];
}
//當手指滑動速度過快就關閉手勢,等停止滾動再開啟手勢
if (offIndex <= -1 || offIndex >= 1) {
self.mainScrollView.userInteractionEnabled = NO;
}
}
- (NSMutableArray *)tagArray {
if (!_tagArray) {
_tagArray = [NSMutableArray arrayWithObjects:@"美食",@"小吃快餐",@"夜生活",@"住宿",@"購物",@"展覽",@"運動",@"體驗",@"餐廳",@"文娛活動"@"興趣",@"酒吧&夜生活",@"酒店",@"景點",@"夜生活", nil];
}
return _tagArray;
}
- (NSMutableArray *)vcArray {
if (!_vcArray) {
_vcArray = [NSMutableArray array];
}
return _vcArray;
}
- (UIScrollView *)topScroll {
if (!_topScroll) {
_topScroll = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 44)];
_topScroll.contentSize = CGSizeMake(0, 0);
}
return _topScroll;
}
- (UIView *)indicatorView {
if (!_indicatorView) {
_indicatorView = [[UIView alloc] init];
_indicatorView.backgroundColor = [UIColor blackColor];
}
return _indicatorView;
}
- (float)getWidthWithTitle:(NSInteger)width andFont:(NSInteger)font andStr:(NSString *)str{
CGRect rectContent = [str boundingRectWithSize:CGSizeMake(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:font]} context:nil];
return rectContent.size.width;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end