OC版写一个快速集成网易新闻,腾讯视频,头条首页的ZJScrollPageView,实现视图联动


最终效果

一.构思部分:

打算分为三个部分, 滑块部分View, 内容显示部分View, 包含滑块View和显示内容View的View,以便于可以灵活的使用

1. 滑块部分View

1.1 要实现滑块可以滚动, 考虑可以直接使用collectionView, 但是这里还是直接使用scrollView方便里面的控件布局

1.2 要实现滑块的点击, 可以直接使用UIButton, 但是经过尝试, 要让button的frame随着文字的宽度来自适应实现比较麻烦, 所以选择了使用UILabel添加点击手势来实现点击事件,这里使用了closures来实现(可以使用代理模式)

1.3 实现对应的滚动条和遮盖同步移动的效果,文字颜色渐变功能(在点击的时候直接使用一个动画就可以简单的完成了)

2. 内容显示部分View

2.1 用来作为包含子控制器的view的容器, 并且实现可以分页滚动的效果

2.2 要实现分页滚动, 可以使用UIScrollView来实现, 但是这样就要考虑UIScrollView上的各个view的复用的问题, 其中细节还是很麻烦, 所以直接使用了UICollectionView(利用他的重用机制)来实现

2.3 将每一个子控制器的view直接添加到对应的每一个cell的contentView中来展示, 所以这里需要注意cell重用可能带来的内容显示不正常的问题, 这里采用了每次添加contentView的内容时移除所有的subviews(也可以直接给每个cell用不同的reuseIdentifier实现)

2.4 实现实时监控滚动的进度提供给滑块部分来同步调整滚动条和遮盖,文字颜色的渐变, 并且在每次滚动完成的时候可以通知给滑块来调整他的内容

3. 包含滑块View和显示内容View的View

3.1 因为滑块部分View和内容显示部分View是相对独立的部分, 在这里只需要实现两者的通信即可

3.2 可以自定义滑块部分View和内容显示部分View的frame

a. 滑块部分

1. 基本属性

// 滚动条
@property (weak, nonatomic) UIView *scrollLine;
// 遮盖
@property (weak, nonatomic) UIView *coverLayer;
// 滚动scrollView
@property (weak, nonatomic) UIScrollView *scrollView;
// 背景ImageView
@property (weak, nonatomic) UIImageView *backgroundImageView;
// 附加的按钮
@property (weak, nonatomic) UIButton *extraBtn;
/// 所有的title设置 -> 使用了一个class ZJSegmentStyle, 将可以自定义的部分全部暴露了出来, 使用的时候就可以比较方便的自定义很多属性  -> 初始化时传入
@property (strong, nonatomic) ZJSegmentStyle *segmentStyle;
// 所有的标题
@property (strong, nonatomic) NSArray *titles;
// 用于懒加载计算文字的rgb差值, 用于颜色渐变的时候设置
@property (strong, nonatomic) NSArray *deltaRGB;
@property (strong, nonatomic) NSArray *selectedColorRgb;
@property (strong, nonatomic) NSArray *normalColorRgb;
/** 缓存所有标题label */
@property (nonatomic, strong) NSMutableArray *titleLabels;
// 缓存计算出来的每个标题的宽度
@property (nonatomic, strong) NSMutableArray *titleWidths;
// 响应标题点击
@property (copy, nonatomic) TitleBtnOnClickBlock titleBtnOnClick;

逻辑处理

#pragma mark - life cycle
- (instancetype)initWithFrame:(CGRect )frame segmentStyle:(ZJSegmentStyle *)segmentStyle titles:(NSArray *)titles titleDidClick:(TitleBtnOnClickBlock)titleDidClick {
    if (self = [super initWithFrame:frame]) {
        self.segmentStyle = segmentStyle;
        self.titles = titles;
        self.titleBtnOnClick = titleDidClick;
        _currentIndex = 0;
        _oldIndex = 0;
        _currentWidth = frame.size.width;

        if (!self.segmentStyle.isScrollTitle) { // 不能滚动的时候就不要把缩放和遮盖或者滚动条同时使用, 否则显示效果不好

            self.segmentStyle.scaleTitle = !(self.segmentStyle.isShowCover || self.segmentStyle.isShowLine);
        }

        // 这个函数里面设置了基本属性中的titles, labelsArray, titlesWidthArray,并且添加了label到scrollView上
        [self setupTitles];
        // 这个函数里面设置了遮盖, 滚动条,和label的初始化位置
        [self setupUI];

    }

    return self;
}

#pragma mark - button action
  -> 处理点击title的时候实现标题的切换,和遮盖,滚动条...的位置调整, 同时执行了相应点击得儿blosure, 以便于外部相应点击方法
- (void)titleLabelOnClick:(UITapGestureRecognizer *)tapGes {

    ZJCustomLabel *currentLabel = (ZJCustomLabel *)tapGes.view;

    if (!currentLabel) {
        return;
    }

    _currentIndex = currentLabel.tag;
    // 同步更改UI
    [self adjustUIWhenBtnOnClickWithAnimate:true];
}

- (void)adjustTitleOffSetToCurrentIndex:(NSInteger)currentIndex  -> 更改scrollview的contentOffSet来居中显示title

     // 手动滚动时需要提供动画效果
- (void)adjustUIWithProgress:(CGFloat)progress oldIndex:(NSInteger)oldIndex currentIndex:(NSInteger)currentIndex -> 提供给外部来执行标题切换之间的动画效果(注意这个方法里面进行了一些简单的数学计算以便于"同步" 滚动滚动条和cell )
    这里以滑块的位置x变化为例, 其他类似

    CGFloat xDistance = currentLabel.zj_x - oldLabel.zj_x;
    这个xDistance就是滑块将要从一个label下面移动到下一个label下面所需要移动的路程,

    这个progress是外界提供来的, 表示当前已经移动的百分比(0 --- 1)是多少了,所以可以改变当前滑块的x为之前的x + 已经完成滚动的距离(xDistance * progress)
    scrollLine?.frame.origin.x = oldLabel.frame.origin.x + xDistance * progress

    这样就达到了滑块的位置随着提供的progress同步移动

    其他的遮盖 和颜色渐变的处理类似

b 内容显示部分View

基本属性

// 用于处理重用和内容的显示
@property (weak, nonatomic) UICollectionView *collectionView;
// collectionView的布局
@property (strong, nonatomic) UICollectionViewFlowLayout *collectionViewLayout;
/** 避免循环引用*/
@property (weak, nonatomic) ZJScrollSegmentView *segmentView;

@property (weak, nonatomic) UIButton *extraBtn;
// 父类 用于处理添加子控制器  使用weak避免循环引用
@property (weak, nonatomic) UIViewController *parentViewController;
// 当这个属性设置为YES的时候 就不用处理 scrollView滚动的计算
@property (assign, nonatomic) BOOL forbidTouchToAdjustPosition;
// 所有的子控制器
@property (strong, nonatomic) NSArray *childVcs;

逻辑处理

#pragma mark - life cycle 

- (instancetype)initWithFrame:(CGRect)frame childVcs:(NSArray *)childVcs segmentView:(ZJScrollSegmentView *)segmentView parentViewController:(UIViewController *)parentViewController {

    if (self = [super initWithFrame:frame]) {
        self.childVcs = childVcs;
        self.parentViewController = parentViewController;
        self.segmentView = segmentView;
        _oldIndex = 0;
        _currentIndex = 1;
        _oldOffSetX = 0.0;
        self.forbidTouchToAdjustPosition = NO;
        // 触发懒加载
        self.collectionView.backgroundColor = [UIColor whiteColor];
        [self commonInit];
    }
    return self;
}

/** 给外界可以设置ContentOffSet的方法 比如点击了标题的时候需要更改内容显示调用*/
- (void)setContentOffSet:(CGPoint)offset animated:(BOOL)animated

/** 给外界刷新视图的方法  用于动态设置子控制器和标题*/
- (void)reloadAllViewsWithNewChildVcs:(NSArray *)newChileVcs {
  // 这种处理是结束子控制器和父控制器的关系
    for (UIViewController *childVc in self.childVcs) {
        [childVc willMoveToParentViewController:nil];
        [childVc.view removeFromSuperview];
        [childVc removeFromParentViewController];
    }

}

#pragma mark - UICollectionViewDelegate --- UICollectionViewDataSource

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.childVcs.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    // 移除subviews 避免重用内容显示错误
    [cell.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    // 这里建立子控制器和父控制器的关系  -> 当然在这之前已经将对应的子控制器添加到了父控制器了, 只不过还没有建立完成
    UIViewController *vc = (UIViewController *)self.childVcs[indexPath.row];
    vc.view.frame = self.bounds;
    [cell.contentView addSubview:vc.view];
    [vc didMoveToParentViewController:self.parentViewController];

    return cell;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView  -> 这个代理方法中处理了滚动的下标和进度  

3. “ZJScrollPageView.h”

这一部分是将segmentView和ContentView封装在一起的, 便于使用者直接使用, 但是您也可以参照这里面的实现, 任意组合segmentView和ContentView的位置, 在demo中也有示例


详细请移步OC源码, swift源码,里面都有详细的Demo使用示例 如果您觉得有帮助,不妨给个star鼓励一下, 欢迎关注


时间: 2024-11-09 20:33:40

OC版写一个快速集成网易新闻,腾讯视频,头条首页的ZJScrollPageView,实现视图联动的相关文章

动手写一个快速集成网易新闻,腾讯视频,头条首页的ScrollPageView,显示滚动视图

更新说明: 2016/04/22 增加自定义选中下标功能, 增加 简书个人主页的使用示例 最终效果 一.构思部分: 打算分为三个部分, 滑块部分View, 内容显示部分View, 包含滑块View和显示内容View的View,以便于可以灵活的使用 1. 滑块部分View 1.1 要实现滑块可以滚动, 考虑可以直接使用collectionView, 但是这里还是直接使用scrollView方便里面的控件布局 1.2 要实现滑块的点击, 可以直接使用UIButton, 但是经过尝试, 要让butto

自己写一个快速开发android模板

自己写一个快速开发android模板 有时候有些代码以前写过,再开发的时候拿来用,就可以节约很多时间,毕竟写过的以前肯定有所了解,再写一次就没必要了,所以这次自己总结出很多应用都需要的一些共性的东西,写到一个模板,以后直接拿来用.首先分析一下: 1.一个应用,首先需要一个欢迎页面,用于展示公司logo啊,或者应用logo,大概展示两三秒. 2.然后就是登陆注册页面,几乎没有应用是没有登陆注册的吧? 3.打印吐司,activity跳转,activity覆盖别的activity,这些基本方法. 4.

快速集成iOS基于RTMP的视频推流

http://www.jianshu.com/p/8ea016b2720e 效果图 iTools有点卡, 但是推到服务器倒是很快的. 推流 前言 这篇blog是iOS视频直播初窥:<喵播APP>的一个补充. 因为之前传到github上的项目中没有集成视频的推流.有很多朋友简信和微博上问我推流这部分怎么实现的. 所以, 我重新集成了RTMP的推流, 合并到了之前的项目中. 下载链接 github(完整版视频直播) blog详解(建议大家结合这篇一起看) Mac搭建nginx+rtmp服务器 我个

新版网易新闻客户端应用源码

源码下载: http://code.662p.com/view/11510.html 演示图:   1.这次更新的亮点是添加了天气效果以后也可以用网易新闻看天气预报了,各种轻微的 动画效果也没有放过. 2.新版的网易新闻,整改了首页UI,在底部加上了tabbar,因此多了很多页面这里也都编了,但是无法交互.毕竟东西太多了,我觉得能点击看到效果就算不能进一步深入,就一个壳子也比全空没有强是吧.. 3.主页-主页的下方加了tabbar,nav的两个 按钮做了改变 4.详情页-详情页对细节的处理更加注

新版网易新闻客户端应用iOS源码

这是一个不错的iOS项目源码. 源码下载: http://code.662p.com/view/11510.html 演示图:   1.这次更新的亮点是添加了天气效果以后也可以用网易新闻看天气预报了,各种轻微的动画效果也没有放过. 2.新版的网易新闻,整改了首页UI,在底部加上了tabbar,因此多了很多页面这里也都编了,但是无法交互.毕竟东西太多了,我觉得能点击看到效果就算不能进一步深入,就一个壳子也比全空没有强是吧.. 3.主页-主页的下方加了tabbar,nav的两个按钮做了改变 4.详情

ios 开发日记 13-剖析网易新闻标签栏视图切换(addChildViewController属性介绍)

iOS开发 剖析网易新闻标签栏视图切换(addChildViewController属性介绍) 时间 2014-06-25 21:45:21  CSDN博客 原文  http://blog.csdn.net/hmt20130412/article/details/34523235 主题 网易iOS开发 本来只是打算介绍一下addChildViewController这个方法的,正好今天朋友去换工作面试问到网易新闻标签栏效果的实现,就结合它,用个小Demo实例介绍一下:(具体解释都写在了Demo里

【转】 iOS开发 剖析网易新闻标签栏视图切换(addChildViewController属性介绍)

原文: http://blog.csdn.net/hmt20130412/article/details/34523235 本来只是打算介绍一下addChildViewController这个方法的,正好今天朋友去换工作面试问到网易新闻标签栏效果的实现,就结合它,用个小Demo实例介绍一下:(具体解释都写在了Demo里面的注释) [objc] view plaincopy // //  HMTMainViewController.m //  UIScrollView // //  Created

iOS开发 剖析网易新闻标签栏视图切换(addChildViewController属性介绍)

本来仅仅是打算介绍一下addChildViewController这种方法的,正好今天朋友去换工作面试问到网易新闻标签栏效果的实现,就结合它,用个小Demo实例介绍一下:(详细解释都写在了Demo里面的凝视) // // HMTMainViewController.m // UIScrollView // // Created by HMT on 14-6-25. // Copyright (c) 2014年 humingtao. All rights reserved. // #import

网易新闻iOS版使用的开源组件

网易新闻iOS版在开发过程中曾经使用过的第三方开源类库.组件 1.AFNetworkingAFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功能强大, 现在许多人都用它取代 ASIHTTPRequest 2.Apple Reachability网络监测,可以参考下这篇文章iOS网络监测如何区分2.3.4G? 3.DOUAudioStreamer豆瓣的开源软件,DOUAudioStreamer 是 i