iOS篇-UI篇-仿今日头条效果父子控制器的应用


代码demo 链接在评论里,喜欢的朋友点个赞.

效果展示:

TZ头条效果

一 科普一分钟:

1.控制器不能被销毁两种 情况 a: 全局 也就是说用strong 指针指向  b:添加成子控制器

比如:我们在 A控制器 的View 添加 B控制器的View  B 中 添加 touchesBegan点击方法  现在我们用一若指针 weak  指向 B 或者几个局部变量B创建所得的View  结果就是 可以看到 B的View 在A .View 中显示 但是点击B 时没有反应 .因为B对象已经被销毁.

2.ARC 管理原则:只要一个对象没有被强引用,就会被销毁.

3.父子控制器运行原理:只要A控制器的View 成为B 控制器View的子视图 那么A控制器 就要成为B控制器的子控制器.

二 代码实现和思路分析:

实现GIF 效果 首先 我们要 建立两个部分,也就是上半部分展示标题的ScrollView 和下半部分展示内容的 ScrollView.

@property(nonatomic,weak)UIScrollView*titleScrollView;

@property(nonatomic,weak)UIScrollView*contentScrollView;

static int const labelWith =100;


添加子控制器 

//添加所有子控制器

-(void)setAllChildController{

//推荐

oneViewController*oneVC = [[oneViewControlleralloc]init];

oneVC.title=@"推荐";

[self addChildViewController:oneVC];

//热点

twoViewController*twoVC = [[twoViewControlleralloc]init];

twoVC.title=@"热点";

[self addChildViewController:twoVC];

//沈阳

threeViewController*threeVC = [[threeViewControlleralloc]init];

threeVC.title=@"沈阳";

[self addChildViewController:threeVC];

//视频

fourViewController*fourVC = [[four ViewControlleralloc]init];

fourVC.title=@"视频";

[self addChildViewController:fourVC];

//社会

fiveViewController*fiveVC = [[fiveViewControlleralloc]init];

fiveVC.title=@"社会";

[self addChildViewController:fiveVC];

//图片

sixViewController*sixVC = [[sixViewControlleralloc]init];

sixVC.title=@"图片";

[self addChildViewController:sixVC];

}

初始化标题ScrollView

-(void)setupScrollView{

NSInteger count =self.childViewControllers.count;

//设置标题滚动条

self.titleScrollView.contentSize=CGSizeMake(count *100,0);

self.titleScrollView.showsHorizontalScrollIndicator=NO;

//设置内容滚动条

self.contentScrollView.contentSize=CGSizeMake(WIDTH*count,0);

//开启分页

self.contentScrollView.pagingEnabled=YES;

//没有弹簧效果

self.contentScrollView.bounces=NO;

//隐藏水平滚动条

self.contentScrollView.showsHorizontalScrollIndicator=NO;

//设置协议

self.contentScrollView.delegate=self;

}

添加所有子控制器对应标题以及标题设置


-(void)setupTitleLabel{

NSInteger count =self.childViewControllers.count;

CGFloat x  =0;

CGFloaty =0;

CGFloat height =44;

for(int i =0; i < count; i++) {

//取出控制器

UIViewController*vc =self.childViewControllers[i];

//创建label

UILabel*label = [[UILabel alloc]init];

//添加label到titleArray数组

[self.titleArray addObject : label];

label.font= [UIFont systemFontOfSize:16];

label.textAlignment=NSTextAlignmentCenter;

x = i*labelWith;

label.tag= i;

//设置尺寸

label.frame=CGRectMake(x, y,labelWith, height);

//设置Label文字

label.text= vc.title;

//添加手势

UITapGestureRecognizer*tap = [[UITapGestureRecognizer alloc] initWithTarget : self action:@selector(titleClick:)];

label.userInteractionEnabled=YES;

[label addGestureRecognizer : tap];

//设置高亮文字颜色

label.highlightedTextColor= [UIColor redColor];

//默认选中第0个label

if(i ==0) {

[self titleClick : tap];

}

//添加label

[self.titleScrollView addSubview : label];

}

}

UI 部分我们搭建完成了,接下来我们来处理 点击标题的业务逻辑 ,我们先分析一下 点击标题label 应该做哪些事情

1.让标题选中,文字为空色

2.滚动到对应的位置

3.对应的位置添加子控制器View

4.让选中标题居中

-(void)titleClick:(UITapGestureRecognizer*)tap{

//0取出label

UILabel*label = (UILabel*)tap.view;

//1.标题颜色高亮

[self selectLabel : label];

//2.滚动相应位置

NSInteger index = label.tag;

//2.1计算滚动位置

CGFloat offsetX = label.tag*WIDTH;

[self.contentScrollView setContentOffset:CGPointMake(offsetX,0)animated:YES];

//3.对应位置添加控制器View

[self showVC : index];

//4.让选中标题居中

[self setUpTitleCenter : label];

}

接下来各个击破里面的方法

首先是 选择 三部曲 创建 临时变量

a:@property(nonatomic,weak)UILabel*seletLabel;

b:做事情

c:参数 label 赋值给 临时变量


-(void)selectLabel:(UILabel*)label{

_seletLabel.highlighted = NO;

//取消形变

_seletLabel.transform=CGAffineTransformIdentity;

_seletLabel.textColor= [UIColor blackColor];

label.highlighted=YES;

//形变

label.transform=CGAffineTransformMakeScale(1.3,1.3);

_seletLabel = label;

}

对应位置添加控制器View 注意的是 优化考虑 加判断 是否被加载过,加载过的视图一律return

-(void)showVC:(NSInteger)index{

CGFloat offsetX = index *WIDTH;

UIViewController*vc =self.childViewControllers[index];

//判断当前控制器的View有没有加载过如果已经加载过就不需要加载

if(vc.isViewLoaded)return;

vc.view.frame=CGRectMake(offsetX,0,WIDTH,self.contentScrollView.frame.size.height);

[self.contentScrollView addSubview: vc.view];

}

让选中标题居中 思路分析

a:滚动的范围就是  标题的中心点 减去 屏幕中心点的距离 就是 移动后的偏移量

b:假如 得出的结果小于0 我们可以分析出 label的其实点在屏幕中心点的左边 也就是 说可以不做事情

c:当滚动到最大的滚动范围之后 在滚动 我们要把滚动范围就设置为最大滚动范围

-(void)setUpTitleCenter:(UILabel*)centerLabel{

//计算偏移量

CGFloat offsetX = centerLabel.center.x-WIDTH*0.5;

if(offsetX <0) {

offsetX =0;

}

//最大滚动范围

CGFloat maxOffsetX =self.titleScrollView.contentSize.width-WIDTH;

if(offsetX > maxOffsetX) {

offsetX = maxOffsetX;

}

//滚动标题滚动条

[self.titleScrollView setContentOffset:CGPointMake(offsetX,0)animated:YES];

}

分析到这里 上半部分的scroll 业务逻辑已经处理完了 ,接下来我们分析 内容的scroll该如何做处理

首先我们写代理方法:滑动结束时,从今日头条 可以分析出,都是滑动停止的时候页面才开始做事情,所以我们要用scrollViewDidEndDecelerating 这个代理方法

思路分析

a:首先和点击标题一样 添加 子控制器View

b:把对应标题选中

c:标题居中

具体方法和上述一样

-(void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView{

//计算滚动到哪一页

NSInteger index = scrollView.contentOffset.x/scrollView.bounds.size.width;

//1.添加子控制器View

[self showVC :index];

//2.把对应标题选中

UILabel*label =self.titleArray[index];

[self selectLabel : label];

//3让选中标题居中

[self setUpTitleCenter :label];

}

最后计算缩放比例 和 字体的渐变

思路分析 :可以看的出来 字体的变化 和颜色的变化 是渐渐产生的,我们会迅速想到的就是scrollView的代理方法 ,而且 无论做任何事 内容scrollView 都是做事情的 所以接下来我们就要在scrollViewDidScroll 这个代理方法里处理

//滚动就会调用

算法分析

a:要想对label 文章首先 我们必须拿到操作的label 通过scrollview的偏移量 / WIDTH 取整数 我们可以知道当前处理的 label  也就是左边的Label 右边label 就是下角标+1

b:字体变化  可以分析出来 右边的label 相对于 左边的 label 的大小 在0-1 之间 增加或者减小

所以  CGFloat currpage = scrollView.contentOffset.x/WIDTH; 得到的currpage 再减去 它的取整 int currpage 就算了 右边 label 对于 左边label 的相对变化  scale 而左边label 相对于右边label的相对变化 就是相反的 1-scale.


-(void)scrollViewDidScroll:(UIScrollView*)scrollView{

CGFloat currpage = scrollView.contentOffset.x/WIDTH;

//左边角标

NSInteger leftIndex = currpage;

//右边角标

NSInteger rightIndex = leftIndex +1;

//获取左边label

UILabel*leftLabel =self.titleArray[leftIndex];

//获取右边label

UILabel*rightLabel;

if(rightIndex <=self.titleArray.count-1) {

rightLabel =self.titleArray[rightIndex];

}

//计算右边缩放比例右边自己相对于左边字体变大比例

CGFloat rightscal = currpage - leftIndex;

//计算左边缩放比例

CGFloat leftscal =1- rightscal;

//缩放比例1~1.3

//左边缩放比例

leftLabel.transform=CGAffineTransformMakeScale(leftscal*0.3+1,leftscal*0.3+1);

//右边缩放比例

rightLabel.transform=CGAffineTransformMakeScale(rightscal*0.3+1,rightscal*0.3+1);

//设置文字颜色渐变

/**RGB渐变*/

leftLabel.textColor= [UIColor colorWithRed :leftscalgreen :0blue:0alpha:1];

rightLabel.textColor= [UIColor colorWithRed :rightscalgreen :0blue:0alpha:1];

}

到这里就是实现了 所有核心 功能 . 相信你可以做的出来一样的效果了.

3总结:

看到页面效果 慢慢分析,从大结构入手 , 每个部分 做了哪些事情 ,能公用的方法要抽取出来.那样方便我们思路分析.下期再见.  ^ _ ^ 不要忘记给个赞

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容