1# transform样式动画
2
3设置transform属性对组件进行旋转、缩放、移动和倾斜。
4
5
6## 设置静态动画
7
8创建一个正方形并旋转90°变成菱形,并用下方的长方形把菱形下半部分遮盖形成屋顶,设置长方形translate属性值为(150px,-150px)确定坐标位置形成门,再使用position属性使横纵线跟随父组件(正方形)移动到指定坐标位置,接着设置scale属性使父子组件一起变大形成窗户大小,最后使用skewX属性使组件倾斜后设置坐标translate(200px,-710px)得到烟囱。
9
10```html
11<!-- xxx.hml -->
12<div class="container">
13  <div class="top"></div>
14  <div class="content"></div>
15  <div class="door"></div>
16  <!-- 窗户 -->
17  <div class="window">
18    <div class="horizontal"></div>
19    <div class="vertical"></div>
20  </div>
21  <div class="chimney"></div>
22</div>
23```
24
25```css
26/* xxx.css */
27.container {
28  width:100%;
29  height:100%;
30  background-color:#F1F3F5;
31  align-items: center;
32  flex-direction: column;
33}
34.top{
35  z-index: -1;
36  position: absolute;
37  width: 428px;
38  height: 428px;
39  background-color: #860303;
40  transform: rotate(45deg);
41  margin-top: 284px;
42  margin-left: 148px;
43}
44.content{
45  margin-top: 500px;
46  width: 600px;
47  height: 400px;
48  background-color: white;
49  border:  1px solid black;
50}
51.door{
52  width: 100px;
53  height: 135px;
54  background-color: #1033d9;
55  transform: translate(150px,-137px);
56}
57.window{
58  z-index: 1;
59  position: relative;
60  width: 100px;
61  height: 100px;
62  background-color: white;
63  border: 1px solid black;
64  transform: translate(-150px,-400px) scale(1.5);
65}
66/* 窗户的横轴 */
67.horizontal{
68  position: absolute;
69  top: 50%;
70  width: 100px;
71  height: 5px;
72  background-color: black;
73}
74/* 窗户的纵轴 */
75.vertical{
76  position: absolute;
77  left: 50%;
78  width: 5px;
79  height: 100px;
80  background-color: black;
81}
82.chimney{
83  z-index: -2;
84  width: 40px;
85  height: 100px;
86  border-radius: 15px;
87  background-color: #9a7404;
88  transform: translate(200px,-710px) skewX(-5deg);
89}
90```
91
92![zh-cn_image_0000001220634677](figures/zh-cn_image_0000001220634677.png)
93
94
95## 设置平移动画
96
97小球下降动画,改变小球的Y轴坐标实现小球下落,在下一段时间内减小Y轴坐标实现小球回弹,让每次回弹的高度逐次减小直至回弹高度为0,就模拟出了小球下降的动画。
98
99```html
100<!-- xxx.hml -->
101<div class="container">
102  <div class="circle"></div>
103  <div class="flower"></div>
104</div>
105```
106
107```css
108/* xxx.css */
109.container {
110  width:100%;
111  height:100%;
112  background-color:#F1F3F5;
113  display: flex;
114  justify-content: center;
115}
116.circle{
117  width: 100px;
118  height: 100px;
119  border-radius: 50px;
120  background-color: red;
121  /* forwards停在动画的最后一帧 */
122  animation: down 3s fast-out-linear-in forwards;
123}
124.flower{
125  position: fixed;
126  width: 80%;
127  margin-left: 10%;
128  height: 5px;
129  background-color: black;
130  top: 1000px;
131}
132@keyframes down {
133  0%{
134    transform: translate(0px,0px);
135  }
136  /* 下落 */
137  15%{
138    transform: translate(10px,900px);
139  }
140  /* 开始回弹 */
141  25%{
142    transform: translate(20px,500px);
143  }
144  /* 下落 */
145  35%{
146    transform: translate(30px,900px);
147  }
148  /* 回弹 */
149  45%{
150    transform: translate(40px,700px);
151  }
152  55%{
153    transform: translate(50px,900px);
154  }
155  65%{
156    transform: translate(60px,800px);
157  }
158  80%{
159    transform: translate(70px,900px);
160  }
161  90%{
162    transform: translate(80px,850px);
163  }
164  /* 停止 */
165  100%{
166    transform: translate(90px,900px);
167  }
168}
169```
170
171![zh-cn_image_0000001174756438](figures/zh-cn_image_0000001174756438.gif)
172
173
174## 设置旋转动画
175
176设置不同的原点位置(transform-origin)改变元素所围绕的旋转中心。rotate3d属性前三个参数值分别为X轴、Y轴、Z轴的旋转向量,第四个值为旋转角度,旋转角度可为负值,负值则代表旋转方向为逆时针方向。
177
178```html
179<!-- xxx.hml -->
180<div class="container">
181  <div class="rotate">
182    <div class="rect rect1"></div>
183    <div class="rect rect2"></div>
184    <div class="rect rect3"></div>
185  </div>
186  <!-- 3d属性 -->
187  <div class="rotate3d">
188    <div class="content">
189        <div class="rect4"></div>
190        <div class="rect5"> </div>
191    </div>
192    <div class="mouse"></div>
193  </div>
194</div>
195```
196
197```css
198/* xxx.css */
199.container {
200    flex-direction: column;
201    background-color:#F1F3F5;
202    display: flex;
203    align-items: center;
204    justify-content: center;
205    width: 100%;
206    height: 100%;
207}
208.rect {
209    width: 100px;
210    height: 100px;
211    animation: rotate 3s infinite;
212    margin-left: 30px;
213}
214.rect1 {
215    background-color: #f76160;
216}
217.rect2 {
218    background-color: #60f76f;
219/* 改变原点位置*/
220    transform-origin: 10% 10px;
221}
222.rect3 {
223    background-color: #6081f7;
224/*  改变原点位置*/
225    transform-origin: right bottom;
226}
227@keyframes rotate {
228    from {
229        transform: rotate(0deg)
230    }
231    to {
232        transform: rotate(360deg);
233    }
234}
235/* 3d示例样式 */
236.rotate3d {
237    margin-top: 150px;
238    flex-direction: column;
239    background-color:#F1F3F5;
240    display: flex;
241    align-items: center;
242    width: 80%;
243    height: 600px;
244    border-radius: 300px;
245    border: 1px solid #ec0808;
246}
247.content {
248    padding-top: 150px;
249    display: flex;
250    align-items: center;
251    justify-content: center;
252}
253/* react4 react5 翻转形成眼睛 */
254.rect4 {
255    width: 100px;
256    height: 100px;
257    animation: rotate3d1 1000ms infinite;
258    background-color: darkmagenta;
259}
260.rect5 {
261    width: 100px;
262    height: 100px;
263    animation: rotate3d1 1000ms infinite;
264    margin-left: 100px;
265    background-color: darkmagenta;
266}
267.mouse {
268    margin-top: 150px;
269    width: 200px;
270    height: 100px;
271    border-radius: 50px;
272    border: 1px solid #e70303;
273    animation: rotate3d2 1000ms infinite;
274}
275/* 眼睛的动效 */
276@keyframes rotate3d1 {
277    0% {
278        transform:rotate3d(0,0,0,0deg)
279    }
280    50% {
281        transform:rotate3d(20,20,20,360deg);
282    }
283    100% {
284        transform:rotate3d(0,0,0,0deg);
285    }
286}
287/* 嘴的动效 */
288@keyframes rotate3d2 {
289    0% {
290        transform:rotate3d(0,0,0,0deg)
291    }
292    33% {
293        transform:rotate3d(0,0,10,30deg);
294    }
295    66% {
296        transform:rotate3d(0,0,10,-30deg);
297    }
298    100% {
299        transform:rotate3d(0,0,0,0deg);
300    }
301}
302```
303
304![zh-cn_image_0000001220316305](figures/zh-cn_image_0000001220316305.gif)
305
306> **说明:**
307>
308> transform-origin变换对象的原点位置,如果仅设置一个值,另一个值为50%,若设置两个值第一个值表示X轴的位置,第二个值表示Y轴的位置。
309
310
311## 设置缩放动画
312
313设置scale样式属性实现涟漪动画,先使用定位确定元素的位置,确定坐标后创建多个组件实现重合效果,再设置opacity属性改变组件不透明度实现组件隐藏与显示,同时设置scale值使组件可以一边放大一边隐藏,最后设置两个组件不同的动画执行时间,实现扩散的效果。
314
315设置sacle3d中X轴、Y轴、Z轴的缩放参数实现动画。
316
317```html
318<!-- xxx.hml -->
319<div class="container">
320  <div class="circle">
321    <text>ripple</text>
322  </div>
323  <div class="ripple"></div>
324  <div class="ripple ripple2"></div>
325  <!-- 3d -->
326  <div class="content">
327    <text>spring</text>
328  </div>
329</div>
330```
331
332```css
333/* xxx.css */
334.container {
335    flex-direction: column;
336    background-color:#F1F3F5;
337    width: 100%;
338    position: relative;
339}
340.circle{
341    margin-top: 400px;
342    margin-left: 40%;
343    width: 100px;
344    height: 100px;
345    border-radius: 50px;
346    background-color: mediumpurple;
347    z-index: 1;  position: absolute;
348}
349.ripple{
350    margin-top: 400px;
351    margin-left: 40%;
352    position: absolute;  z-index: 0;
353    width: 100px;
354    height: 100px;
355    border-radius: 50px;
356    background-color: blueviolet;
357    animation: ripple 5s infinite;
358}
359/* 设置不同的动画时间 */
360.ripple2{
361    animation-duration: 2.5s;
362}
363@keyframes ripple{
364    0%{
365        transform: scale(1);
366        opacity: 0.5;
367    }
368    50%{
369        transform: scale(3);
370        opacity: 0;
371    }
372    100%{
373        transform: scale(1);
374        opacity: 0.5;
375    }
376}
377text{
378    color: white;
379    text-align: center;
380    height: 100%;
381    width: 100%;
382}
383.content {
384    margin-top: 700px;
385    margin-left: 33%;
386    width: 200px;
387    height: 100px;
388    animation:rubberBand 1s infinite;
389    background-color: darkmagenta;
390    position: absolute;
391}
392@keyframes rubberBand {
393    0% {
394        transform: scale3d(1, 1, 1);
395    }
396    30% {
397        transform: scale3d(1.25, 0.75, 1.1);
398    }
399    40% {
400        transform: scale3d(0.75, 1.25, 1.2);
401    }
402    50% {
403        transform: scale3d(1.15, 0.85, 1.3);
404    }
405    65% {
406        transform: scale3d(.95, 1.05, 1.2);
407    }
408    75% {
409        transform: scale3d(1.05, .95, 1.1);
410    }
411    100%{
412        transform: scale3d(1, 1, 1);
413    }
414}
415```
416
417![zh-cn_image_0000001220396251](figures/zh-cn_image_0000001220396251.gif)
418
419> **说明:**
420>
421> 设置transform属性值后,子元素会跟着父元素一起改变,若只改变父元素其他属性值时(如:height,width),子元素不会改变。
422
423
424## 设置matrix属性
425
426matrix是一个入参为六个值的矩阵,6个值分别代表:scaleX, skewY, skewX, scaleY, translateX, translateY。下面示例中设置 了matrix属性为matrix(1,0,0,1,0,200)使组件移动和倾斜。
427
428```html
429<!-- xxx.hml -->
430<div class="container">
431  <div class="rect"> </div>
432</div>
433```
434
435```css
436/* xxx.css */
437.container{
438  background-color:#F1F3F5;
439  display: flex;
440  justify-content: center;
441  width: 100%;
442  height: 100%;
443}
444.rect{
445  width: 100px;
446  height: 100px;
447  background-color: red;
448  animation: down 3s infinite forwards;
449}
450@keyframes down{
451  0%{
452    transform: matrix(1,0,0,1,0,0);
453  }
454  10%{
455    transform: matrix(1,0,0,1,0,200);
456  }
457  60%{
458    transform: matrix(2,1.5,1.5,2,0,700);
459  }
460  100%{
461    transform: matrix(1,0,0,1,0,0);
462  }
463}
464```
465
466![zh-cn_image_0000001174756580](figures/zh-cn_image_0000001174756580.gif)
467
468
469## 整合transform属性
470
471transform可以设置多个值并且多个值可同时设置,下面案例中展示同时设置缩放(scale),平移(translate),旋转(rotate)属性时的动画效果。
472
473```html
474<!-- xxx.hml -->
475<div class="container">
476  <div class="rect1"></div>
477  <div class="rect2"></div>
478  <div class="rect3"></div>
479  <div class="rect4"></div>
480  <div class="rect5"></div>
481</div>
482```
483
484```css
485/* xxx.css */
486.container{
487    width: 100%;
488    height: 100%;
489    flex-direction:column;
490    background-color:#F1F3F5;
491    padding:50px;
492}
493.rect1{
494    width: 100px;
495    height: 100px;
496    background-color: red;
497    animation: change1 3s infinite forwards;
498}
499.rect2{
500    margin-top: 50px;
501    width: 100px;
502    height: 100px;
503    background-color: darkblue;
504    animation: change2 3s infinite forwards;
505}
506.rect3{
507    margin-top: 50px;
508    width: 100px;
509    height: 100px;
510    background-color: darkblue;
511    animation: change3 3s infinite;
512}
513.rect4{
514    align-self: center;
515    margin-left: 50px;
516    margin-top: 200px;
517    width: 100px;
518    height: 100px;
519    background-color: darkmagenta;
520    animation: change4 3s infinite;
521}
522.rect5{
523    margin-top: 300px;
524    width: 100px;
525    height: 100px;
526   background-color: cadetblue;
527    animation: change5 3s infinite;
528}
529/* change1 change2 对比 */
530@keyframes change1{
531    0%{
532        transform: translate(0,0);    transform: rotate(0deg)
533    }
534    100%{
535        transform: translate(0,500px);
536        transform: rotate(360deg)
537    }
538}
539/* change2 change3 对比属性顺序不同的动画效果 */
540@keyframes change2{
541    0%{
542        transform:translate(0,0) rotate(0deg) ;
543    }
544    100%{
545        transform: translate(300px,0) rotate(360deg);
546    }
547}
548@keyframes change3{
549    0%{
550        transform:rotate(0deg) translate(0,0);
551    }
552    100%{
553        transform:rotate(360deg)  translate(300px,0);
554    }
555}
556/* 属性值不对应的情况 */
557@keyframes change4{
558    0%{
559        transform: scale(0.5);
560    }
561    100%{
562        transform:scale(2) rotate(45deg);
563    }
564}
565/* 多属性的写法 */
566@keyframes change5{
567    0%{
568        transform:scale(0) translate(0,0) rotate(0);
569    }
570    100%{
571        transform: scale(1.5) rotate(360deg) translate(200px,0);
572    }
573}
574```
575
576![zh-cn_image_0000001220554911](figures/zh-cn_image_0000001220554911.gif)
577
578> **说明:**
579> - 当设置多个transform时,后续的transform值会把前面的覆盖掉。若想同时使用多个动画样式可用复合写法,例:transform: scale(1) rotate(0) translate(0,0)。
580>
581> - transform进行复合写法时,变化样式内多个样式值顺序的不同会呈现不一样的动画效果。
582>
583> - transform属性设置的样式值要一一对应,若前后不对应,则该动画不生效。若设置多个样式值则只会呈现出已对应值的动画效果。
584
585
586## 相关实例
587
588针对transform样式动画开发,有以下相关实例可供参考:
589
590- [`JsClock`:时钟(JS)(API10)](https://gitee.com/openharmony/applications_app_samples/tree/master/code/Solutions/Tools/JsClock)
591
592- [动画样式(JS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/JSUI/AnimationDemo)
593
594- [图片常见操作(JS)(API9)](https://gitee.com/openharmony/codelabs/tree/master/Media/ImageOperation)
595