本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。

这一节继续和大家探讨iOS中的动画效果,由于网易新闻中的动画效果比较多,所以我分两个章节进行介绍。这一节介绍的效果就是 头部导航切换效果。效果图如下:

一、需求分析:

1. 点击某个Item后,这个Item文字变大,颜色变成红色;其余的Item,文字正常大小显示,颜色变成黑色。

2. 在滚动切换的时候,涉及到的两个Item会线性渐变:将要"离开"的Item,文字变小,颜色从红色慢慢过渡到黑色;将要"到达" 的Item,文字变大,颜色从黑色慢慢过渡到红色。

3. Item下面对应的内容不是一次性加载的。只有第一次点击Item或者第一次滚动切换到对应的内容才加载,以后再切换到这里的时候,直接显示。比如:Demo中,"百度"切换到 "阿里",只有等到手松开并且滚动到 "阿里" 的时候,里面对应的内容才加载。以后再切换到 "阿里" 的时候,就不需要再次加载了。

二、代码分析:

1. 由于上面头部的导航效果与具体的业务逻辑没有多大关系,所以我们可以自定义一个View来实现它。

2. 下面显示的内容,我们不可预测(有可能直接是一个View,有可能是从一个控制器中获取的View...), 所以这一部分代码直接在主控制器中实现即可。

三、代码实现:

1. 自定义头部导航,命名为NavHeaderView。由于自定义头部的逻辑比较简单,我就不一一作解释了,只说明关键部分的代码:

2. NavHeaderView.h文件

@interface NavHeaderView : UIView
// 切换tab上面index的block回调
@property (nonatomic, copy) void (^indexChangeBlock)(NSUInteger index);
// 初始化tab
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray *)titles;
// 在滚动过程中,tab上面的item的渐变效果的实现
- (void)transformItemStyleWithContentOffsetX:(CGFloat)offsetX;
// 直接点击tab上面的item,切换选中项
- (void)changeItemStyleWithIndex:(NSInteger)index;
@end

3. NavHeaderView.m文件

#import "NavHeaderView.h"
#import "UIColor+RGBA.h"#define kMinFontSize 17
#define kMaxFontSize 24
#define kDelta (kMaxFontSize - kMinFontSize)
#define kNavWidth self.frame.size.width@interface NavHeaderView()
@property (nonatomic, assign) CGFloat itemWidth;
@property (nonatomic, assign) NSUInteger currentIndex;
@property (nonatomic, strong) NSMutableArray *lbls;
@end@implementation NavHeaderView- (NSMutableArray *)lbls {if (!_lbls) {_lbls = [NSMutableArray array];}return _lbls;
}- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray *)titles {if (self = [super initWithFrame:frame]) {NSInteger count = titles.count;CGFloat width = frame.size.width;self.itemWidth = width / count;CGFloat height = frame.size.height;for (NSUInteger i = 0; i < count; i++) {UILabel *label = [[UILabel alloc] init];label.tag = i;label.frame = CGRectMake(i * self.itemWidth, 0, self.itemWidth, height);label.text = titles[i];label.tintColor = [UIColor blackColor];label.textAlignment = NSTextAlignmentCenter;label.userInteractionEnabled = YES;label.font = [UIFont systemFontOfSize:kMinFontSize];[self addSubview:label];[self.lbls addObject:label];}UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];[self addGestureRecognizer:tapGesture];self.currentIndex = 0;[self changeItemStyleWithIndex:0];}return self;
}- (void)tap:(UITapGestureRecognizer *)gesture {CGPoint point = [gesture locationInView:gesture.view];NSUInteger index = floor(point.x / self.itemWidth);self.currentIndex = index;[self changeItemStyleWithIndex:index];if (self.indexChangeBlock) {self.indexChangeBlock(index);}
}- (void)changeItemStyleWithIndex:(NSInteger)index {for (UILabel *lbl in self.lbls) {if (lbl.tag == index) {UIColor *selectedColor = [UIColor redColor];lbl.textColor = selectedColor;lbl.font = [UIFont systemFontOfSize:kMaxFontSize];} else {UIColor *normalColor = [UIColor blackColor];lbl.textColor = normalColor;lbl.font = [UIFont systemFontOfSize:kMinFontSize];}}
}

3-1) initWithFrame:titles: 方法就是使用UILabel来显示tab上面的文字。

3-2) changeItemStyleWithIndex: 方法就是实现切换Item,来改变文字显示的大小和颜色。

4. 添加渐变效果

4-1) 渐变效果算法分析:

4-2) 代码实现:

首先,我们需要定义两组颜色属性,用来计算颜色过渡的效果,属性定义如下:

@property (nonatomic, assign) CGFloat  red1;
@property (nonatomic, assign) CGFloat  green1;
@property (nonatomic, assign) CGFloat  blue1;
@property (nonatomic, assign) CGFloat  alpha1;
@property (nonatomic, assign) CGFloat  red2;
@property (nonatomic, assign) CGFloat  green2;
@property (nonatomic, assign) CGFloat  blue2;
@property (nonatomic, assign) CGFloat  alpha2;

其次,我们需要改造 changeItemStyleWithIndex: 方法,初始化以上所定义的属性值。

- (void)changeItemStyleWithIndex:(NSInteger)index {for (UILabel *lbl in self.lbls) {if (lbl.tag == index) {UIColor *selectedColor = [UIColor redColor];lbl.textColor = selectedColor;RGBA rgba = RGBAFromUIColor(selectedColor);self.red1 = rgba.r;self.green1 = rgba.g;self.blue1 = rgba.b;self.alpha1 = rgba.a;lbl.font = [UIFont systemFontOfSize:kMaxFontSize];} else {UIColor *normalColor = [UIColor blackColor];lbl.textColor = normalColor;RGBA rgba = RGBAFromUIColor(normalColor);self.red2 = rgba.r;self.green2 = rgba.g;self.blue2 = rgba.b;self.alpha2 = rgba.a;lbl.font = [UIFont systemFontOfSize:kMinFontSize];}}
}

最后,实现滚动代码,来完成文字大小及颜色渐变的效果。

- (void)transformItemStyleWithContentOffsetX:(CGFloat)offsetX {if (offsetX <= 0) {UILabel *firstLabel = [self.lbls firstObject];CGFloat currentFontsize = kMaxFontSize - fabs(offsetX) / kNavWidth * kDelta;firstLabel.font = [UIFont systemFontOfSize:currentFontsize];CGFloat redTemp = self.red1 + (self.red2 - self.red1) * fabs(offsetX) / kNavWidth;CGFloat greenTemp = self.green1 + (self.green2 - self.green1) * fabs(offsetX) / kNavWidth;CGFloat blueTemp = self.blue1 + (self.blue2 - self.blue1) * fabs(offsetX) / kNavWidth;firstLabel.textColor = [UIColor colorWithRed:redTemp green:greenTemp blue:blueTemp alpha:1.0];} else if (offsetX >= kNavWidth * (self.lbls.count - 1)) {UILabel *lastLabel = [self.lbls lastObject];CGFloat modWidth = fmod(offsetX, kNavWidth);CGFloat currentFontsize = kMaxFontSize - modWidth / kNavWidth * kDelta;lastLabel.font = [UIFont systemFontOfSize:currentFontsize];CGFloat redTemp = self.red1 + (self.red2 - self.red1) * modWidth / kNavWidth;CGFloat greenTemp = self.green1 + (self.green2 - self.green1) * modWidth / kNavWidth;CGFloat blueTemp = self.blue1 + (self.blue2 - self.blue1) * modWidth / kNavWidth;lastLabel.textColor = [UIColor colorWithRed:redTemp green:greenTemp blue:blueTemp alpha:1.0];} else {NSLog(@"offsetX:%f", offsetX);NSInteger index = offsetX / kNavWidth;UILabel *preLabel = self.lbls[index];UILabel *nextLabel = self.lbls[index + 1];NSLog(@"mod:%f", fmod(offsetX, kNavWidth));CGFloat percent = fmod(offsetX, kNavWidth) / kNavWidth;CGFloat preFont = kMaxFontSize - percent * kDelta;CGFloat nextFont = kMinFontSize + percent * kDelta;preLabel.font = [UIFont systemFontOfSize:preFont];nextLabel.font = [UIFont systemFontOfSize:nextFont];CGFloat redPrev = self.red1 + (self.red2 - self.red1) * percent;CGFloat greenPrev = self.green1 + (self.green2 - self.green1) * percent;CGFloat bluePrev = self.blue1 + (self.blue2 - self.blue1) * percent;preLabel.textColor = [UIColor colorWithRed:redPrev green:greenPrev blue:bluePrev alpha:1.0];CGFloat redNext = self.red1 + (self.red2 - self.red1) * (1 - percent);CGFloat greenNext = self.green1 + (self.green2 - self.green1) * (1 - percent);CGFloat blueNext = self.blue1 + (self.blue2 - self.blue1) * (1 - percent);nextLabel.textColor = [UIColor colorWithRed:redNext green:greenNext blue:blueNext alpha:1.0];}
}

5. 主控制器,初始化自定义的NavHeaderView, 实现相应的代码:

5-1) viewDidLoad 代码中完成了自定义NavHeaderView的初始化工作。

5-2) createMenuScrollView 方法创建内容区域的view。

5-3) createMenuViewSubViewIndex: 方法这里就实现了"按需" 加载对应的内容区域,默认是加载的第一个。

- (void)viewDidLoad {[super viewDidLoad];CGRect frame = CGRectMake(0, 60, self.view.frame.size.width, 44);NSArray *titles = @[@"百度", @"阿里", @"腾讯", @"爱奇艺"];self.headerView = [[NavHeaderView alloc] initWithFrame:frame titles:titles];self.headerView.backgroundColor = [UIColor greenColor];__weak typeof(self) weakSelf = self;self.headerView.indexChangeBlock = ^(NSUInteger index){[weakSelf createMenuViewSubViewWithIndex:index];[weakSelf.menuScrollView setContentOffset:CGPointMake(index * frame.size.width, 0) animated:NO];};[self.view addSubview:self.headerView];[self createMenuScrollView];
}- (void)createMenuScrollView {CGFloat menuY = 104;CGFloat menuHeight = self.view.frame.size.height - menuY;CGRect frame = CGRectMake(0, menuY, self.view.frame.size.width, menuHeight);self.menuScrollView = [[UIScrollView alloc] initWithFrame:frame];self.menuScrollView.contentSize = CGSizeMake(self.view.frame.size.width * 4, menuHeight);self.menuScrollView.pagingEnabled = YES;self.menuScrollView.delegate = self;[self.view addSubview:self.menuScrollView];[self createMenuViewSubViewWithIndex:0];
}- (void)createMenuViewSubViewWithIndex:(NSInteger)index {//根据需要创建 菜单详情View 而不是一次创建完if (0 == index) {[self createFirstView];} else if (1 == index) {[self createSecondView];} else if (2 == index) {[self createThirdView];} else if (3 == index) {[self createForthView];}
}- (void)createFirstView {if (self.firstView) {return;}self.firstView = [LFFirstView firstView];CGFloat width = self.menuScrollView.bounds.size.width;CGFloat height = self.menuScrollView.bounds.size.height;CGFloat x = 0;CGFloat y = 0;self.firstView.frame = CGRectMake(x, y, width, height);[self.menuScrollView addSubview:self.firstView];
}

6. 实现主控制器中内容区域的UIScrollView的代理方法,完成头部文字切换及渐变的效果。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {CGFloat offsetX = scrollView.contentOffset.x;[self.headerView transformItemStyleWithContentOffsetX:offsetX];
}- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {CGFloat offsetX = scrollView.contentOffset.x;CGFloat width = scrollView.bounds.size.width;NSInteger index = offsetX / width;[self createMenuViewSubViewWithIndex:index];[self.headerView changeItemStyleWithIndex:index];
}

至此,仿网易新闻头部文字切换的效果就算完成了,下一节给大家介绍,网易新闻中 "排序及删除" 动画效果的实现。

动画特效十五:网易新闻之头部导航切换效果相关推荐

  1. photoshop第十五章:制作商业卡片场景效果

    第十五章:制作商业卡片场景效果 1.制作证件寸照效果 素材: 效果: (1)Ctrl+N新建文件->名称:证件寸照->宽度:14厘米->高度:14厘米->分辨率:300像素/英 ...

  2. 爬虫技术 -- 进阶学习(十)网易新闻页面信息抓取(htmlagilitypack搭配scrapysharp)...

    最近在弄网页爬虫这方面的,上网看到关于htmlagilitypack搭配scrapysharp的文章,于是决定试一试~ 于是到https://www.nuget.org/packages/Scrapy ...

  3. Android典型界面设计(3)——访网易新闻实现双导航tab切换

    一.问题描述 双导航tab切换(底部区块+区域内头部导航),实现方案底部区域使用FragmentTabHost+Fragment, 区域内头部导航使用ViewPager+Fragment,可在之前博客 ...

  4. android tabhost 动画,Android中使用TabHost 与 Fragment 制作页面切换效果

    三个标签页置于顶端 效果图: 在文件BoardTabHost.java中定义页面切换的效果:切换页面时,当前页面滑出,目标页面滑入.这是2个不同的动画设定动画时要区分对待 import android ...

  5. 动画特效十四:手风琴效果

    本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看. 在讲解JQuery特效的时候,我介绍过 手风琴效果; 这一节我讲解一下在iOS中的实现效果:相对 ...

  6. 第二十二章:动画(十五)

    深入动画 在第一次遇到时,完整的Xamarin.Forms动画系统可能会有点混乱. 让我们从可用于定义动画的三个公共类的全局视图开始. 整理课程 除了Easing类之外,Xamarin.Forms动画 ...

  7. Android动画之属性动画,android开发网易新闻

    1.透明动画:alpha 2.位移动画:translationX,translationY 3.旋转动画:rotation 4.缩放动画:scaleX,scaleY 5.组合显示:AnimatorSe ...

  8. 四十五、使用bootstrap制作导航条

    使用bootstrap制作导航条 参考链接:https://v3.bootcss.com/components/#navbar 项目结构 工具使用: Bootstrap Button Generato ...

  9. 仿照网易新闻旧版本左拉的列表动画效果

    最近网易新闻客户端更新之后个人感觉不如从前,以前点击左上角的汉堡包菜单按钮的时候,整个屏幕会右移然后出现列表菜单,还有列表的动画效果(外围的圆圈会先放大然后缩小,选中的栏目图标有特殊的动画).在网易新 ...

最新文章

  1. 分布式服务治理框架Dubbo
  2. 通知 | 2021年度“RONG”奖学金入围答辩名单公布
  3. aria2下载工具命令行和图形化界面使用
  4. 替换k个字符后最长重复子串
  5. Dephi7程序设计与开发技术大全(求是科技)
  6. 「递归」第8集 | 当敲代码的手开始写歌,玩跨界的程序员有多野?
  7. 规避软件架构风险之反模式
  8. 世界首富比尔·盖茨的母亲有多厉害?
  9. 【报告分享】2022中国人工智能人才培养报告.pdf(附下载链接)
  10. 爬虫python能做什么-python爬虫能干什么
  11. 除了富二代 据说这9种人最有富豪潜质
  12. Emacs之multi-occur(替代grep)
  13. 5.13 利用图层的矢量蒙版打造浪漫情调 [原创Ps教程]
  14. 好的计算机书籍 http://outmyth.blogdriver.com/outmyth/1122212.html
  15. NVIDIA NCCL 源码学习(一)- 初始化及ncclUniqueId的产生
  16. 对token(令牌)的理解
  17. 传奇关于首饰盒装备系统“十二生肖”“五行八卦”等脚本实例
  18. 主动外观模型(AAM)
  19. 慢聊Go之Go常见的Web 开发框架
  20. C#中File和FileInfo的区别和用法

热门文章

  1. Java回炉学习(一)
  2. Linux文件目录管理、文件内容查看以及文件内容查询命令(详细命令)
  3. java获取当前时间前12个月内的年月信息
  4. ESP32在线语音识别 词法解析
  5. 使用UltraISO软碟通制作Win10PE启动U盘
  6. OB2263MP小知识
  7. debian 安装打印机驱动及打印机共享
  8. java把URL转换成二维码并保存在指定的位置
  9. Python+Vue计算机毕业设计“爱尚”农产品销售平台的设计与实现3fuz0(程序+LW+源码+部署)
  10. 神经网络的三种训练方法,如何训练一个神经网络