第十四篇、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
原文地址:https://www.cnblogs.com/HJQ2016/p/6104603.html