第十四篇、OC_新闻查看器
PageTitleView:
#import <UIKit/UIKit.h> @class GFBPageTitleView; @protocol GFBPageTitleViewDelegate <NSObject> - (void)pageTitleView:(GFBPageTitleView *)pageTitleView selectedIndex:(int)index; @end @interface GFBPageTitleView : UIView - (instancetype)initWithFrame:(CGRect)frame titles:(NSArray *)titlesArray; @property (nonatomic,weak)id<GFBPageTitleViewDelegate> delegate; - (void)setTitleWithProgress:(CGFloat)progress soureceIndex:(int)sourceIndex targetIndex:(int)targetIndex; @end
// // GFBPageTitleView.m // elmsc // // Created by MAC on 2016/11/26. // Copyright © 2016年 GFB Network Technology Co.,Ltd. All rights reserved. // #import "GFBPageTitleView.h" // 线条的高度 #define kScrollLineH 2.0 @interface GFBPageTitleView () @property (nonatomic, strong) NSArray *titlesArray; @property (nonatomic, strong) NSMutableArray *titlesLabelArray; @property (nonatomic, strong) UIScrollView *contentScrollView; @property (nonatomic, strong) UIView *scrollLineView; @property (nonatomic, assign) NSInteger currentIndex; @end @implementation GFBPageTitleView #pragma mark--懒加载 - (UIScrollView *)contentScrollView { if (! _contentScrollView) { _contentScrollView = [[UIScrollView alloc]init]; _contentScrollView.showsHorizontalScrollIndicator = NO; _contentScrollView.scrollsToTop = NO; _contentScrollView.bounces = NO; } return _contentScrollView; } - (UIView *)scrollLineView { if (! _scrollLineView) { _scrollLineView = [[UIView alloc]init]; _scrollLineView.backgroundColor = [UIColor orangeColor]; } return _scrollLineView; } - (instancetype)initWithFrame:(CGRect)frame titles:(NSArray *)titlesArray { self = [super initWithFrame:frame]; if (self) { self.titlesArray = titlesArray; [self setUpUI]; return self; } return nil; } #pragma mark--Private Methods 自定义方法 - (void) setUpUI { self.titlesLabelArray = [NSMutableArray array]; // 添加滚动视图 [self addSubview:self.contentScrollView]; self.contentScrollView.frame = self.bounds; // 添加title对应的Label [self setUpTitleLabels]; // 设置底线和滚动的滑块 [self setupBottomLineAndScrollLine]; } - (void) setUpTitleLabels { // 0.确定label的一些frame的值 CGFloat labelW = self.frame.size.width / (CGFloat)(self.titlesArray.count); CGFloat labelH = self.frame.size.height - kScrollLineH; CGFloat labelY = 0; [self.titlesArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UILabel *label = [[UILabel alloc]init]; label.text = obj; label.tag = idx; label.font = [UIFont systemFontOfSize:16]; label.textColor = [UIColor lightGrayColor]; label.textAlignment = NSTextAlignmentCenter; CGFloat labelX = labelW * (CGFloat)(idx); label.frame = CGRectMake(labelX, labelY, labelW, labelH); [self.contentScrollView addSubview:label]; [self.titlesLabelArray addObject:label]; // 添加到数组中 // 添加手势点击 label.userInteractionEnabled = YES; // 允许交互 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(titleLabelClick:)]; [label addGestureRecognizer:tap]; }]; } - (void) setupBottomLineAndScrollLine { // 1.添加底线(底部的线暂时不需要) UIView *bottomLine = [UIView new]; bottomLine.backgroundColor = [UIColor lightGrayColor]; CGFloat lineH = 0.5; bottomLine.frame = CGRectMake(0, self.frame.size.height - lineH, self.frame.size.width, lineH); //[self addSubview:bottomLine]; // 2.添加scrollLine // 2.1.获取第一个Label UILabel *firstLabel = self.titlesLabelArray.firstObject; firstLabel.textColor = [UIColor lightGrayColor]; // 2.2.设置scrollLine的属性 [self.contentScrollView addSubview:self.scrollLineView]; self.scrollLineView.frame = CGRectMake(firstLabel.frame.origin.x, self.frame.size.height - kScrollLineH, firstLabel.frame.size.width, kScrollLineH); } #pragma mark--Action 点击方法 - (void) titleLabelClick:(UITapGestureRecognizer *)tapGes { // 0.获取当前Label UILabel *currentLabel = (UILabel *)tapGes.view; // 1.如果是重复点击同一个Title,那么直接返回 if (currentLabel.tag == self.currentIndex) { return; } // 2.获取之前的Label UILabel *oldLabel = self.titlesLabelArray[_currentIndex]; // 3.切换文字的颜色 currentLabel.textColor = [UIColor lightGrayColor]; //UIColor(r: kSelectColor.0, g: kSelectColor.1, b: kSelectColor.2) oldLabel.textColor = [UIColor lightGrayColor]; //UIColor(r: kNormalColor.0, g: kNormalColor.1, b: kNormalColor.2) // 4.保存最新Label的下标值 self.currentIndex = currentLabel.tag; // 5.滚动条位置发生改变 CGFloat scrollLineX = (CGFloat)(_currentIndex) * self.scrollLineView.frame.size.width; [UIView animateWithDuration:0.15 animations:^{ CGRect rect = self.scrollLineView.frame; rect.origin.x = scrollLineX; self.scrollLineView.frame = rect; }]; // 通知代理 [self.delegate pageTitleView:self selectedIndex:(int)self.currentIndex]; } #pragma mark--对外的方法 - (void)setTitleWithProgress:(CGFloat)progress soureceIndex:(int)sourceIndex targetIndex:(int)targetIndex { // 1.取出sourceLabel/targetLabel UILabel *sourceLabel = self.titlesLabelArray[sourceIndex]; UILabel *targetLabel = self.titlesLabelArray[targetIndex]; // 2.处理滑块的逻辑 CGFloat moveTotalX = targetLabel.frame.origin.x - sourceLabel.frame.origin.x; CGFloat moveX = moveTotalX * progress; CGRect rect = self.scrollLineView.frame; rect.origin.x = sourceLabel.frame.origin.x + moveX; self.scrollLineView.frame = rect; // 3.颜色的渐变(复杂) // 3.1.取出变化的范围 // let colorDelta = (kSelectColor.0 - kNormalColor.0, kSelectColor.1 - kNormalColor.1, kSelectColor.2 - kNormalColor.2) // 3.2.变化sourceLabel sourceLabel.textColor = [UIColor lightGrayColor]; //UIColor(r: kSelectColor.0 - colorDelta.0 * progress, g: kSelectColor.1 - colorDelta.1 * progress, b: kSelectColor.2 - colorDelta.2 * progress) // 3.2.变化targetLabel targetLabel.textColor = [UIColor lightGrayColor]; //UIColor(r: kNormalColor.0 + colorDelta.0 * progress, g: kNormalColor.1 + colorDelta.1 * progress, b: kNormalColor.2 + colorDelta.2 * progress) // 4.记录最新的index self.currentIndex = targetIndex; } @end
PageContentView:
// // GFBPageContentView.h // elmsc // // Created by MAC on 2016/11/26. // Copyright © 2016年 GFB Network Technology Co.,Ltd. All rights reserved. // #import <UIKit/UIKit.h> @class GFBPageContentView; @protocol GFBPageContentViewDelegate <NSObject> - (void)pageContentView:(GFBPageContentView *)view progress:(CGFloat)progress sourceIndex:(int)sourceIndex targetIndex:(int)targetIndex; @end @interface GFBPageContentView : UIView // 重写方法 - (instancetype)initWithFrame:(CGRect)frame childVcs:(NSMutableArray *) vcArray parentViewController:(UIViewController *) controller; // 对外的暴露方法 -(void)setCurrentIndex:(int)currentIndex; @property (nonatomic, weak)id<GFBPageContentViewDelegate> delegate; @end
// // GFBPageContentView.m // elmsc // // Created by MAC on 2016/11/26. // Copyright © 2016年 GFB Network Technology Co.,Ltd. All rights reserved. // #import "GFBPageContentView.h" static NSString *ContentCellID = @"ContentCellID"; @interface GFBPageContentView ()<UICollectionViewDataSource,UICollectionViewDelegate,UIScrollViewDelegate> @property (nonatomic, strong) UICollectionView *contentCollectView; @property (nonatomic, strong) NSMutableArray *childVcArray; @property (nonatomic, weak) UIViewController *parentViewController; @property (nonatomic, assign) CGFloat startOffsetX; @property (nonatomic, assign) BOOL isForbidScrollDelegate; @end @implementation GFBPageContentView #pragma mark--懒加载 - (UICollectionView *) contentCollectView { if (! _contentCollectView) { // 创建布局 UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init]; layout.itemSize = self.bounds.size; layout.minimumInteritemSpacing = 0; layout.minimumLineSpacing = 0; layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; // 2.创建UICollectionView _contentCollectView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout]; _contentCollectView.showsHorizontalScrollIndicator = NO; _contentCollectView.pagingEnabled = YES; _contentCollectView.bounces = NO; _contentCollectView.dataSource = self; _contentCollectView.delegate = self; _contentCollectView.scrollsToTop = NO; _contentCollectView.backgroundColor = [UIColor whiteColor]; [_contentCollectView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:ContentCellID]; } return _contentCollectView; } #pragma mark--Systems Methods 系统方法 - (instancetype)initWithFrame:(CGRect)frame childVcs:(NSMutableArray *) vcArray parentViewController:(UIViewController *) controller { self = [super initWithFrame:frame]; if (self) { self.childVcArray = vcArray; self.parentViewController = controller; [self setUpUI]; return self; } return nil; } #pragma mark--Private Methods 自定义方法 私有 - (void) setUpUI{ self.startOffsetX = 0; self.isForbidScrollDelegate = NO; for (UIViewController *vc in self.childVcArray) { [self.parentViewController addChildViewController:vc]; } [self addSubview:self.contentCollectView]; self.contentCollectView.frame = self.bounds; } #pragma mark--对外的暴露方法 // 对外的暴露方法 -(void)setCurrentIndex:(int)currentIndex { // 1.记录需要进制执行代理方法 self.isForbidScrollDelegate = YES; // 2.滚动正确的位置 CGFloat offsetX = (CGFloat)(currentIndex) * self.contentCollectView.frame.size.width; [self.contentCollectView setContentOffset:CGPointMake(offsetX, 0) animated:NO]; } #pragma mark-UICollectionView Methods 数据源方法 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.childVcArray.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ContentCellID forIndexPath:indexPath]; // 给cell设置内容 for (id view in cell.contentView.subviews) { [view removeFromSuperview]; } UIViewController *vc = self.childVcArray[indexPath.item]; vc.view.frame = cell.contentView.bounds; [cell.contentView addSubview:vc.view]; return cell; } #pragma mark - UIScrollerViewDelegate Methods 代理方法 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { self.isForbidScrollDelegate = NO; self.startOffsetX = scrollView.contentOffset.x; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // 0.判断是否是点击事件 if (self.isForbidScrollDelegate) { return; } // 1.定义需要的数据 CGFloat progress = 0; int sourceIndex = 0; int targetIndex = 0; // 2.判断是左滑还是右滑 CGFloat currentOffsetX = scrollView.contentOffset.x; CGFloat scrollViewW = scrollView.bounds.size.width; if (currentOffsetX > self.startOffsetX) { // 左滑 // 1.计算progress progress = currentOffsetX / scrollViewW - floor(currentOffsetX / scrollViewW); // 2.计算sourceIndex sourceIndex = (int)(currentOffsetX / scrollViewW); // 3.计算targetIndex targetIndex = sourceIndex + 1; if (targetIndex >= self.childVcArray.count) { targetIndex = (int)self.childVcArray.count - 1; } // 4.如果完全划过去 if (currentOffsetX - self.startOffsetX == scrollViewW) { progress = 1; targetIndex = sourceIndex; } }else{ // 右滑 // 1.计算progress progress = 1 - (currentOffsetX / scrollViewW - floor(currentOffsetX / scrollViewW)); // 2.计算targetIndex targetIndex = (int)(currentOffsetX / scrollViewW); // 3.计算sourceIndex sourceIndex = targetIndex + 1; if (sourceIndex >= self.childVcArray.count) { sourceIndex = (int)self.childVcArray.count - 1; } } [self.delegate pageContentView:self progress:progress sourceIndex:sourceIndex targetIndex:targetIndex]; } @end
使用:
// // GFBTypeGoodsDetailViewController.m // elmsc // // Created by MAC on 2016/11/26. // Copyright © 2016年 GFB Network Technology Co.,Ltd. All rights reserved. // #import "GFBTypeGoodsDetailViewController.h" #import "GFBPageTitleView.h" #import "GFBPageContentView.h" #import "GFBCommentViewController.h" #import "GFBProductViewController.h" #import "GFBProuctDetailViewController.h" @interface GFBTypeGoodsDetailViewController ()<GFBPageTitleViewDelegate,GFBPageContentViewDelegate> @property (nonatomic, strong) GFBPageTitleView *pageTitleView; @property (nonatomic, strong) GFBPageContentView *pageContentView; @end @implementation GFBTypeGoodsDetailViewController #pragma mark--懒加载 - (GFBPageTitleView *)pageTitleView { if (! _pageTitleView) { NSMutableArray *arry = [NSMutableArray arrayWithObjects:@"产品",@"详情",@"评价", nil]; _pageTitleView = [[GFBPageTitleView alloc]initWithFrame:CGRectMake(0, 0, 160 * frameW / 375.0, 28) titles:arry]; _pageTitleView.delegate = self; } return _pageTitleView; } - (GFBPageContentView *)pageContentView { if (! _pageContentView) { NSMutableArray *vcArray = [NSMutableArray array]; // 产品 GFBProductViewController *productVc = [GFBProductViewController new]; // 详情 GFBProuctDetailViewController *productDetailVc = [GFBProuctDetailViewController new]; // 评论 GFBCommentViewController *commentVc = [GFBCommentViewController new]; [vcArray addObject:productVc]; [vcArray addObject:productDetailVc]; [vcArray addObject:commentVc]; _pageContentView = [[GFBPageContentView alloc]initWithFrame:CGRectMake(0, 0, frameW, frameH - 64) childVcs:vcArray parentViewController:self]; //NSLog(@"当前的高度%f",self.view.bounds.size.height); _pageContentView.delegate = self; } return _pageContentView; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.title = @"商品详情"; } - (void)viewDidLoad { [super viewDidLoad]; [self setUpUI]; } #pragma mark-Private Methods 自定义方法 - (void) setUpUI { [self setUpNavBar]; [self setUpContentView]; } - (void) setUpNavBar { self.navigationItem.titleView = self.pageTitleView; } - (void) setUpContentView { [self.view addSubview:self.pageContentView]; } #pragma mark-GFBPageTitleViewDelegate Method - (void)pageTitleView:(GFBPageTitleView *)pageTitleView selectedIndex:(int)index { [self.pageContentView setCurrentIndex:index]; } #pragma mark-GFBPageContentViewDelegate Method - (void)pageContentView:(GFBPageContentView *)view progress:(CGFloat)progress sourceIndex:(int)sourceIndex targetIndex:(int)targetIndex { [self.pageTitleView setTitleWithProgress:progress soureceIndex:sourceIndex targetIndex:targetIndex]; } @end