仿网易新闻架构

  • 头部标题选择,切换控制器


    WechatIMG1.jpeg
  • 实现思路

  • 类似于tabbar 首先添加子控制器

  • 添加标题选择按钮

  • 通过实现scrollView的代理方法,实现控制器的切换,懒加载

  • 默认启动时选择第一个头部标题

-(void)viewDidLoad {
    [super viewDidLoad];
    //添加子控制器
    [self setUpChildVc];
    //添加标题选择按钮
    [self setUpTitle];
    //选择第一个
    [self scrollViewDidEndScrollingAnimation:self.contentScrollView]; 
}
  • 添加子控制器 [self addChildViewController:social0];将控制器加到子控制器数组中对其引用,否则控制器创建后就会被杀死
  • 如下添加七个控制器
-(void)setUpChildVc{
    ZZHTableViewController *social0 = [[ZZHTableViewController alloc] init];
    social0.title = @"头1";
    [self addChildViewController:social0];
    ZZHTableViewController *social1 = [[ZZHTableViewController alloc] init];
    social1.title = @"头2";
    [self addChildViewController:social1];    
    ZZHTableViewController *social2 = [[ZZHTableViewController alloc] init];
    social2.title = @"头3";
    [self addChildViewController:social2];   
    ZZHTableViewController *social3 = [[ZZHTableViewController alloc] init];
    social3.title = @"头4";
    [self addChildViewController:social3];   
    ZZHTableViewController *social4 = [[ZZHTableViewController alloc] init];
    social4.title = @"头5";
    [self addChildViewController:social4];    
    ZZHTableViewController *social5 = [[ZZHTableViewController alloc] init];
    social5.title = @"头6";
    [self addChildViewController:social5];    
    ZZHTableViewController *social6 = [[ZZHTableViewController alloc] init];
    social6.title = @"头7";
    [self addChildViewController:social6]; 
}
  • 添加头部标题选择按钮
  • 如下根据子控制器数组中的数量,添加标题,标题即为控制器的title,social0.title = @"头1"
-(void)setUpTitle{
    // 定义临时变量
    CGFloat labelW = 100;
    CGFloat labelY = 0;
    CGFloat labelH = self.titleScrollView.frame.size.height;
    NSInteger count = self.childViewControllers.count;
    // 添加label
    for (NSInteger i = 0; i<count; i++) {
        ZZHLabel *label = [[ZZHLabel alloc] init];
        label.text = [self.childViewControllers[i] title];
        CGFloat labelX = i * labelW;
        label.frame = CGRectMake(labelX, labelY, labelW, labelH);
        label.tag = i;
        [self.titleScrollView addSubview:label];
        //label添加点击手势
        UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
        [label addGestureRecognizer:tap];
    }
    // 设置contentSize
    self.titleScrollView.contentSize = CGSizeMake(count * labelW, 0);
    self.contentScrollView.contentSize = CGSizeMake(count * [UIScreen mainScreen].bounds.size.width, 0);
}
  • 给每个label添加点击事件,通过tag记录每个label的index,通过点击设置scrollView的ContentOffset来切换控制器
-(void)tap:(UITapGestureRecognizer *)tap{
    // 取出被点击label的索引
    NSInteger index = tap.view.tag;
    // 让底部的内容scrollView滚动到对应位置
    CGPoint offset = self.contentScrollView.contentOffset;
    offset.x = index * self.contentScrollView.frame.size.width;
    [self.contentScrollView setContentOffset:offset animated:YES];
}
  • 实现scrollView 的代理方法
  • 用户用手滑动scroll时 和通过点击头部标题用代码控制scroll滑动触发的代理方法是不同的,所以这里要实现两个代理方法
  • scrollView结束了滚动动画以后就会调用这个方法(比如-(void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;方法执行的动画完毕后)
#pragma mark - <UIScrollViewDelegate>
//scrollView结束了滚动动画以后就会调用这个方法(比如- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;方法执行的动画完毕后)
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
    // 一些临时变量
    CGFloat width = scrollView.frame.size.width;
    CGFloat height = scrollView.frame.size.height;
    CGFloat offsetX = scrollView.contentOffset.x;
    // 当前位置需要显示的控制器的索引
    NSInteger index = offsetX / width;
    // 让对应的顶部标题居中显示
    ZZHLabel *label = self.titleScrollView.subviews[index];
    CGPoint titleOffset = self.titleScrollView.contentOffset;
    titleOffset.x = label.center.x - width * 0.5;
    // 左边超出处理
    if (titleOffset.x < 0) titleOffset.x = 0;
    // 右边超出处理
    CGFloat maxTitleOffsetX = self.titleScrollView.contentSize.width - width;
    if (titleOffset.x > maxTitleOffsetX) titleOffset.x = maxTitleOffsetX;
    [self.titleScrollView setContentOffset:titleOffset animated:YES];
    // 让其他label回到最初的状态
    for (ZZHLabel *otherLabel in self.titleScrollView.subviews) {
        if (otherLabel != label) otherLabel.scale = 0.0;
    }
    // 取出需要显示的控制器
    UIViewController *willShowVc = self.childViewControllers[index];
    // 如果当前位置的位置已经显示过了,就直接返回
    if ([willShowVc isViewLoaded]) return;
    // 添加控制器的view到contentScrollView中;
    willShowVc.view.frame = CGRectMake(offsetX, -64, width, height);
    [scrollView addSubview:willShowVc.view]; 
}
  • 手指松开scrollView后,scrollView停止减速完毕就会调用这个-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
//手指松开scrollView后,scrollView停止减速完毕就会调用这个
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self scrollViewDidEndScrollingAnimation:scrollView];
}
  • 在滑动中获得需要处理的两个label 对label的font和color进行缩放,渐变处理
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat scale = scrollView.contentOffset.x / scrollView.frame.size.width;
    if (scale < 0 || scale > self.titleScrollView.subviews.count - 1) return;
    // 获得需要操作的左边label
    NSInteger leftIndex = scale;
    ZZHLabel *leftLabel = self.titleScrollView.subviews[leftIndex];
    // 获得需要操作的右边label
    NSInteger rightIndex = leftIndex + 1;
    ZZHLabel *rightLabel = (rightIndex == self.titleScrollView.subviews.count) ? nil : self.titleScrollView.subviews[rightIndex];
    // 右边比例
    CGFloat rightScale = scale - leftIndex;
    // 左边比例
    CGFloat leftScale = 1 - rightScale;
    // 设置label的比例
    leftLabel.scale = leftScale;
    rightLabel.scale = rightScale;
}
  • 将label的font缩放color渐变的效果封装到ZZHLabel中,通过暴露@property (nonatomic, assign) CGFloat scale;属性,重写- (void)setScale:(CGFloat)scale对label进行设置
const CGFloat XMGRed = 0.4;
const CGFloat XMGGreen = 0.6;
const CGFloat XMGBlue = 0.7;
const CGFloat XMGAlpha = 1.0;
-(void)setScale:(CGFloat)scale
{
    _scale = scale;
    //      R G B
    // 默认:0.4 0.6 0.7
    // 红色:1   0   0
    CGFloat red = XMGRed + (1 - XMGRed) * scale;
    CGFloat green = XMGGreen + (0 - XMGGreen) * scale;
    CGFloat blue = XMGBlue + (0 - XMGBlue) * scale;
    self.textColor = [UIColor colorWithRed:red green:green blue:blue alpha:XMGAlpha];
    // 大小缩放比例
    CGFloat transformScale = 1 + scale * 0.3; // [1, 1.3]
    self.transform = CGAffineTransformMakeScale(transformScale, transformScale);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容