您现在的位置是:主页 > news > 网站域名的意思/广州seo全网营销
网站域名的意思/广州seo全网营销
admin2025/5/13 15:01:13【news】
简介网站域名的意思,广州seo全网营销,建筑模板批发市场,免费微网站_自助建站前言 记得以前看到过一个很赞的文字效果的动画,类似于这样: 当时被惊艳到了,最近偶然间又再次见到,依然还是那么喜欢。假设我们现在需要实现这样的需求。一般碰到需求我们都会去 GitHub 上看看,俗称找轮子(…
前言
记得以前看到过一个很赞的文字效果的动画,类似于这样:
当时被惊艳到了,最近偶然间又再次见到,依然还是那么喜欢。假设我们现在需要实现这样的需求。一般碰到需求我们都会去 GitHub 上看看,俗称找轮子(GitHub 基本上只有你想不到的,就没有它没有的)。大多数情况下,没有问题。或者说有点小问题:轮子太多,无从下嘴。
选择
选轮子就像选姑娘,你不知道后面等着你的是什么 —–罪恶坑小程如是说
程序员江湖,每位大侠的武功和套路不尽一样,少林,武当,昆仑各门各派,百花争艳。实现轮子的思路自然也不一样。有的轮子高深晦涩难懂,功能强大,有的清晰明了,功能简单。不过有一点相同是,选错了就会被坑,只是坑大坑小问题。选轮子自然需要无比谨慎,既要匹配需求同时也要能在掉坑里的时候填上(废话,出 bug 了,你不填,谁填),要能 hold 住。然而填坑哪能那么简单呢,首先轮子实现思路,代码的结构,运行时序你要搞清楚吧,提供了哪些功能,没提供哪些功能,你要了解吧。基本上一个复杂点的轮子,研究下来就要好些时间了。这还不包括你开会,沟通,解 bug,喝茶,倒水,上厕所,抽烟,骂娘,吐槽产品需求的时间。所以,妹子们,不要问我们今天加不加班,要问今天能不能在你睡前下班。(项目快上线了,小程不加班谁加班。嗯哼。)
创造
如果能用代码扮演上帝话,苍老师的量产不是问题,就看产品经理定的需求是拟物还是扁平。—-罪恶坑小程如是说
既然选轮子的时间成本也不低,那有时候我们可以自己造一个轮子。其实写一个的好处也多,有成就感,写好了可以吹牛逼,写坏了填坑速度快。但问题是,以前没写过怎么办?没把握怎么办?比如我们现在需要实现上面的文字效果,但是又不知道怎么写,怎么办?
没关系,上帝创造世间也分了七步走,跟着这位带头大哥后面学,总不会错的。
开始
罗马不是一天建成的,毛片不是一次性拍完的 —-罪恶坑小程如是说
咦,好像扯得有点多了。对不起,现在开始正式拍(苍老师准备下,小程也准备下,Action):
1. 分解任务
通过简单观察我们可以马上知道,上面那个动画效果是通过对每个字符做动画完成的。而在 iOS 里,文本显示控件最常见和常用的是 UILabel。而 iOS 的 Explicit Animation 有 Properties Animation 和 keyframe Animation 两种。
但是 UILabel 控件没有提供对其 Text 中每个字符的控制的功能,我们需要改造下。既然要对每个字符做动画,那少不了需要frame
,bounds
,position
,transform
,这些属性。
这样看来我们需要两个武器:一个做排版功能的 framework,不用说,肯定是 TextKit。而另一个是能显示单个字符也拥有frame
,bounds
,position
,transform
等属性的类,很自然,我们想到CATextLayer
。
2. 先解决文本布局
TextKit 里主要是三个类 NSTextStorage
,NSLayoutManager
,NSContainer
。它们一起帮组我们解决文字布局,排版的工作。
-
NSTextStorage:
NSMutableAttributedString
的子类,持有文字内容,当字符发生改变时,通知NSLayoutManager
对象 -
NSLayoutManager: 我们的男主角,从
NSTextStorage
里获取文字内容后,转换成对应的 glyph,根据NSTextContainer
的 visible Region 显示 glyph。 -
NSContainer: 确定一个 region 来放置 text。这个 region 被
NSLayoutManager
用来决定哪里可以 break lines
不过可惜 UILabel 没有这三个类作为自己的属性对象,我们需要自己解决:
|
除此以外我们还需要两个 Array 用来保存文本变换前的旧字符和变换后的新字符:
|
因为我们需要用我们自己的 textStorage 对象,所以我们需要覆盖 text 和 attributedText 等属性。
|
当 TextStorage 的文本内容改变时,会触发一个通知 send textLayoutManager 以便重新布局排版。显然我们可以在排版布局完成后来为每个字符创建设置一个 CATextLayer,并设置相应的 frame 以便正确的显示内容。我们可以有个函数来完成计算。并且 layout finish 完成时调用。
|
接下来我们的主要想法,是找到 text 里每个 character 以及对应的 glyph rect. 然后用 character 和 glyph rect 创建 CATextLayer
首先我们要有一个空数组用来存放新的 CATextLayer。并且获取 textStorage 的 attributedText。
|
接下来我们要通过 LayoutManger 找到 TextContainer 的 used Rect,这样方便我们可以让文本垂直居中,就像普通的 Label 那样。
|
现在我们开始迭代处理文本里的每个字符,创建一个 glyphRange 并且用这个 glyphRange 找到对应的 character,然后我们将 glyph index 丢给 LayoutManager 得到 textContainer,再用 container 和 glyphRange 取得 glyphRect(这里需要注意下 kerning 的问题)。
|
最终我们还需要注意的就是 glyph 的 kerning,如果 kerningRange.location == index
,我们需要将前一个 textLayer 取出来调整其 Rect 的宽度至新的 glyphRect 的最右边,保证 glyph 不会被裁切掉(可以对比下面两张图片)
|
这里关于 kerning 和 glyph 要多说一点。先来说下 glyph,简单来说 glyph 是表示一个 character 的具体样式 , 但他们却不是一一对应的关系,比如一个字母 “A” 可以有不同的写法来表示例如:
除此以外,还有这种情况:
上面是的 “ff” 虽然是两个 character,但是 glyph 却是一个。
不过不用担心,强大 LayoutManager 提供了两个方法帮助我们通过一个找到对应另外那个。
|
现在我们说下 kerning。通常,在水平排布的文本中,glyph 都是一个挨着一个放置的,但是在某些时候为了让文本的可读性更好,看上去更加优雅美观,一个字形和另外一个字形之间可能会稍微的错位下,比如下面这种情况:
这也是上面为什么”Y“会出现显示不全的原因了。
接下来就比较简单了,创建 Textlayer, 设置垂直居中,添加到数组当中,index += characterRange.length
,开始下次循环
|
3. 动画实现
上面我们解决了字符排版的问题,接下来动画的实现就相对的容易了,仔细观察那个动画,很容易得出主要是对 opacity
和 transform
两个属性做属性动画,opacity
让每个字体逐渐显示和逐渐消失,而 transform
则做了两种变形,一种是往下移动,另外一种是旋转。用 CABasicAnimation
可以解决单个属性动画,而 CAAnimationGroup
则帮我们解决多个动画叠加的复合效果。
|
这里需要注意一个问题,就是隐式动画的问题,Core Animation 基于一个假说,就是屏幕上的任何东西都可以 (或者可能) 做动画,我们平时在写代码时应该有这种印象就是你只是 layer 设置了一个值,没有添加动画,但是你会看到一个平滑过渡的显示效果而不是非常突兀的变化。这就是隐式动画。当我们改变一个属性时,Core Animation 帮我们做了一个动画,动画时间取决于当前 NSTransaction 的设置,而动画类型取决于图层行为。
这里有个有趣的东西,多说一点,就是当我们对 UIView 关联的图层做动画而不是一个单独的图层做动画,比如
|
图层的颜色瞬间切换到新的值,而不是之前的平滑过渡,隐式动画似乎给关闭了。
我们知道 UIView 和 CALayer 最重要的关系就是 UIView 是 CALayer 的 delegate,
当我们改变 CALayer 的属性时,它会调用 func actionForKey(_ event: String) -> CAAction?
这个方法,接下来发生的事情在官方文档里都有写,实际上是如下几步:
-
If the layer has a delegate that implements the actionForLayer:forKey: method, the layer calls that method. The delegate must do one of the following:
-
Return the action object for the given key.
-
Return the NSNull object if it does not handle the action.
-
-
The layer looks in the layer’s actions dictionary for a matching key/action pair.
- The layer looks in the style dictionary for an actions dictionary for a matching key/action pair.
- The layer calls the defaultActionForKey: class method to look for any class-defined actions.
UIView 作为它关联图层的 Delegate,实现了 actionForLayer(_ layer: CALayer, forKey event: String) -> CAAction?
,当不在一个动画块中,UIView 返回 nil,而在动画块中则返回一个非空值
|
显示结果如下
|
当然返回 nil 并不是禁用隐式动画的唯一方法,下面这样也行
|
那为什么说这个问题呢?因为我们在对每个字符做动画的时候需要先将隐式动画关闭,否者将会做两次动画,比如下面这样:
那么,我们先生成一份 oldlayer, 然后改变相应的属性,生产新的 newLayer。然后创建相应的动画组,添加显式动画。
|