iOS--如何写一个微博导航栏动画(CoreGraphics)

前言

昨天刚做完项目的新版本、除了尝试一些新的架构之外、功能方面并没什么特别的地方。
但是顺手搞了一些还算好玩的东西、其一就是这个导航栏的动画。
感觉还算简单易懂、分享一下(其实更多是最近攒了好多封面、不贴出来憋得人难受)

导航栏动画.gif

思路

先介绍CA的两个方法:
  • 基于原始状态的位移
CG_EXTERN CGAffineTransform CGAffineTransformMakeTranslation(CGFloat tx,
  CGFloat ty) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
  • 基于原始状态的形变
CG_EXTERN CGAffineTransform CGAffineTransformScale(CGAffineTransform t,
  CGFloat sx, CGFloat sy) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

知道了这两个方法、剩下就是如何使用形变和位移以达到想要的效果了。

这里、需要分两部分来看、一部分是位移、一部分是形变
而且、如果将一整个动画以及翻页动作看成1。那么位移和形变又需要分成两部分来看:0到0.5以及0.5到1。

其实一点都不难、画个图看一眼。连一元方程都不算、完全是小学算术题~甚至连奥数都算不上。

0到0.5区间内

  • 先看形变

在0.5时、我们需要将线条长度从left_width形变成max_width

形变-0到0.5

  • 再看位移

与此同时如果想让线条在左侧看起来并没有移动、就需要将线条的x轴一点点向右移动。这个移动的值呢?
由于形变是双向的、右侧和左侧都会变长。那么对于左侧最终将是中间时最终形变差值的一半。
具体到数值:
最左侧到中心点时x轴的位移 = 最左侧到中心点时形变的差值/2 = (max_width - left_width)/2

0.5到1区间内

  • 依旧先看形变

和之前的形变相同


形变-0.5到1
  • 然后来看位移

同理、如果我的长度减少了X、那么我如果想保证看起来右侧位置不会改变、考虑到形变是左右同时发生、就需要向右移动X/2。
具体到数值:
中心点到最右侧时x轴的位移 = 中心点到最右时形变的差值/2 = (max_width - right_width)/2


具体函数

以我项目里两个按钮(self.titleBtn1/self.titleBtn2)为例

if (0 <= offsetRate && offsetRate <= 0.5) {
        /*
         * 左侧与中间相互移动
         */
        
        //x轴位移 :: 中间时位移 * 偏移比例系数
        CGFloat translationOfX = _translationofX_center * offsetRate * 2;
        self.line.transform = CGAffineTransformMakeTranslation(translationOfX, 0);
        
        //x轴形变 :: 1 + (最大时相对形变) * 偏移比例系数
        CGFloat flagScale = 1 + (_flagScale_center - 1) * (offsetRate * 2);
        self.line.transform = CGAffineTransformScale(self.line.transform, flagScale, 1);
        
    }else if (0.5 < offsetRate && offsetRate <= 1) {
        /*
         * 中间与右侧相互移动
         */
        
        //x轴位移 :: 中间时位移 + 最终位移 * 偏移比例系数
        CGFloat translationOfX = _translationofX_center + _translationofX_right * (offsetRate - 0.5) * 2;
        self.line.transform = CGAffineTransformMakeTranslation(translationOfX, 0);
        
        //x轴形变 :: 最大时形变 - (最大形变 - 最终形变) * 偏移比例系数
        CGFloat flagScale = _flagScale_center - (_flagScale_center - _btn2Width/_btn1Width) * (offsetRate - 0.5) * 2;

        self.line.transform = CGAffineTransformScale(self.line.transform, flagScale, 1);
    }

其中的某些参数的意义以及取值:

{
    //整体最大宽度
    CGFloat _maxWidth;
    //位于左侧时宽度
    CGFloat _btn1Width;
    //位于右侧时宽度
    CGFloat _btn2Width;
    //从左侧移到中心时x轴位移
    CGFloat _translationofX_center;
    //从中心移到右侧时x轴位移
    //所以总位移就是_translationofX_center+_translationofX_right
    CGFloat _translationofX_right;
    //位于中心时形变
    CGFloat _flagScale_center;
}

{
    _btn1Width = self.titleBtn1.width;
    _btn2Width = self.titleBtn2.width;
    _maxWidth = self.titleBtn2.right - self.titleBtn1.left;
    _translationofX_center = (_maxWidth - _btn1Width)/2;
    _translationofX_right = (_maxWidth - _btn2Width)/2;
    _flagScale_center = _maxWidth/_btn1Width;
    self.line.frame = CGRectMake(self.titleBtn1.left, self.height, self.titleBtn1.width, 1);
}

将屏幕滑动的偏移量传递进来

#pragma mark UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    CGFloat offsetX = scrollView.contentOffset.x;
    CGFloat offsetRate = offsetX/BSScreen_Width;
    

    //将偏移率传递给navView
    
    [self.navView configLingWithOffsetRate:offsetRate];

}


Demo

上面的例子的代码其实都已经列出来了、没什么再单独传Demo的必要。
但是毕竟开了个帖子、连个Demo都没有不好看。于是上午干脆封装了一个小工具出来。
但是只封装了移动的动画、并没封装按钮变色等等一系列功能。

KTNavDemo.gif

用起来也挺简单的、只要将按钮的数组下方横线交付、在屏幕滑动的时候把偏移量传递进去、就能自动工作了。宽度啊什么都会自己算:

@interface KTNavScrollTool : NSObject


/**
 初始化

 @param titleArr 按钮数组
 @param line 需要移动的横线
 @return 实例对象
 */
- (instancetype)initWithTitleArr:(NSArray<UIView *> *)titleArr line:(UIView *)line;


/**
 移动的函数

 @param offsetRate scrollview滚动式的偏移量的比例
 */
- (void)configLingWithOffsetRate:(CGFloat)offsetRate;
@end

GitHub有兴趣可以自取

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