PlAnimateHeadline
한 줄이 위의 줄을 타이머에 맞춰 대신합니다. 모든 줄이 같은 그리드 칸에 있어서 상자는 첫 프레임부터 가장 긴 줄만큼 크고, 릴이 돌아도 크기가 변하지 않습니다.
import { PlAnimateHeadline } from 'plass-ui';
<PlAnimateHeadline interval={2200}>
<span>ships on Friday</span>
<span>reads like prose</span>
<span>weighs almost nothing</span>
</PlAnimateHeadline>;import 'package:plass_ui/plass_ui.dart';
const PlAnimateHeadline(
interval: Duration(milliseconds: 2200),
children: <Widget>[
Text('ships on Friday'),
Text('reads like prose'),
Text('weighs almost nothing'),
],
);Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| interval | number | 2600 | 다음 줄이 올라오기까지 한 줄을 붙들어 두는 시간(ms). 줄이 도착한 순간부터 세므로 주기 길이가 아니라 읽는 시간입니다 |
| index | number | — | 어느 줄이 떠 있는지. 넘기면 릴을 직접 몰 수 있고, 컴포넌트는 자기 타이머를 돌리지 않습니다 |
| defaultIndex | number | 0 | uncontrolled 릴이 시작하는 자리 |
| onIndexChange | (index: number) => void | — | 방금 올라온 줄과 함께 호출됩니다 |
| loop | boolean | true | 마지막 줄 다음에 다시 시작합니다. 끄면 마지막 줄에서 멈춰 그대로 있습니다 |
| rise | number | string | '100%' | 줄이 올라오거나 나갈 때 이동하는 거리. '100%'는 줄 하나의 높이입니다 |
| duration공통 | number | 460 | 한 번 도는 데 걸리는 시간(ms). CSS 문자열이 아니라 숫자입니다 |
| delay공통 | number | 0 | 시작하기까지 기다리는 시간(ms) |
| easing공통 | string | the house curve | CSS가 쓰는 그대로의 이징 곡선 |
| repeat공통 | number | 'infinite' | 'infinite' | 몇 번 반복할지. 끝없이 돌리려면 Infinity가 아니라 'infinite' — CSS에 그 단어로 그대로 쓰이기 때문입니다 |
| paused공통 | boolean | false | 있는 자리에 멈춰 세웁니다 |
| trigger공통 | 'mount' | 'visible' | 'hover' | 'manual' | 'mount' | 무엇이 시작시키는지. mount는 화면에 올라오자마자, visible은 스크롤되어 보일 때, hover는 포인터나 focus가 닿을 때, manual은 play가 시킬 때만 |
| play공통 | boolean | — | trigger가 manual일 때 실행합니다. false → true가 될 때마다 처음부터 다시 돕니다 |
| once공통 | boolean | true | trigger="visible"에서 처음 한 번만 돌릴지. 끄면 화면에 다시 들어올 때마다 다시 돕니다 |
| threshold공통 | number | 0.2 | trigger="visible"에서 얼마나 보여야 보이는 것으로 칠지, 0에서 1 사이 |
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| children * | List<Widget> | — | 읽어야 할 순서대로의 줄들 |
| interval | Duration | Duration(milliseconds: 2600) | 다음 줄이 올라오기까지 한 줄을 붙들어 두는 시간(ms). 줄이 도착한 순간부터 세므로 주기 길이가 아니라 읽는 시간입니다 |
| index | int? | — | 어느 줄이 떠 있는지. 넘기면 릴을 직접 몰 수 있고, 컴포넌트는 자기 타이머를 돌리지 않습니다 |
| defaultIndex | int | 0 | uncontrolled 릴이 시작하는 자리 |
| onIndexChange | ValueChanged<int>? | — | 방금 올라온 줄과 함께 호출됩니다 |
| loop | bool | true | 마지막 줄 다음에 다시 시작합니다. 끄면 마지막 줄에서 멈춰 그대로 있습니다 |
| rise | double? | one line's own height | 줄이 올라오거나 나갈 때 이동하는 거리(논리 픽셀). null이면 줄 하나의 높이입니다 |
| duration공통 | Duration | Duration(milliseconds: 460) | 한 번 도는 데 걸리는 시간(ms). CSS 문자열이 아니라 숫자입니다 |
| delay공통 | Duration | Duration.zero | 시작하기까지 기다리는 시간(ms) |
| curve공통 | Curve? | the house curve | CSS가 쓰는 그대로의 이징 곡선 |
| repeat공통 | int? | null | 몇 번 반복할지. null이 멈추지 않음을 뜻합니다 — 적을 'infinite'가 없고, -1은 찾아봐야 하는 sentinel입니다 |
| paused공통 | bool | false | 있는 자리에 멈춰 세웁니다 |
| trigger공통 | PlassAnimateTrigger | PlassAnimateTrigger.mount | 무엇이 시작시키는지. mount는 화면에 올라오자마자, visible은 스크롤되어 보일 때, hover는 포인터나 focus가 닿을 때, manual은 play가 시킬 때만 |
| play공통 | bool | false | trigger가 manual일 때 실행합니다. false → true가 될 때마다 처음부터 다시 돕니다 |
| once공통 | bool | true | trigger="visible"에서 처음 한 번만 돌릴지. 끄면 화면에 다시 들어올 때마다 다시 돕니다 |
| threshold공통 | double | 0.2 | trigger="visible"에서 얼마나 보여야 보이는 것으로 칠지, 0에서 1 사이 |
네이티브 <div> 속성은 그대로 통과합니다. render도 alternate도 없습니다. 컴포넌트가 자기 그리드를 있고, 릴에는 돌아갈 다른 방향이 없습니다.
rise는 논리 픽셀 단위의 double?이고, 기본값인 null이 줄 하나의 높이입니다. PlAnimateSlide의 distance와 같은 거래죠. alternate는 없습니다. 릴에는 돌아갈 다른 방향이 없습니다.
interval은 주기의 시작이 아니라 줄이 도착한 순간부터 셉니다. 그래서 duration을 올려도 읽는 시간이 조용히 깎이지 않습니다.
나머지 공유 설정 — duration, delay, easing, repeat, paused, trigger, play, once, threshold — 은 다른 곳에서와 같은 뜻입니다. delay는 릴이 돌기 시작하기 전에 일어나는 일이므로 줄마다가 아니라 한 번만 더해집니다.
Examples
Controlled
index를 넘기면 릴이 자기 타이머를 돌리지 않습니다. controlled headline은 다른 누군가의 시계이고, 그 아래에서 두 번째 시계가 돌면 같은 상태를 두고 다투게 됩니다. 폼의 단계, 탭, 또는 직접 가진 타이머로 돌리세요.
rise
줄이 올라오거나 나갈 때 이동하는 거리입니다. '100%'는 줄 하나의 높이이고, 릴처럼 읽히게 만드는 것이 그것입니다. 몇 픽셀이면 방향이 살짝 있는 crossfade에 가깝습니다.
Accessibility
prefers-reduced-motion에서도 줄은 바뀌지만 미끄러지지는 않습니다. 나가는 줄은 애니메이션 없이 사라집니다. 릴 자체가 내용이므로, 통째로 끄면 첫 줄만 남습니다.- 읽는 사람이 반드시 봐야 하는 내용에는 쓰지 마세요. 한 줄이 떠 있는 2초 동안 누가 보고 있으리라는 보장이 없고, 스크린리더는 묶음이 아니라 마침 떠 있는 줄을 받습니다. 어느 것이었어도 괜찮았을 문구들에 쓰세요.
- 모든 줄은 첫 프레임부터 문서에 있고, 떠 있지 않은 줄은 레이아웃에서 빠지는 대신
visibility로 자리를 지킵니다. 상자가 크기를 바꾸지 않는 이유이고, 아무것도 두 번 읽히지 않는 이유이기도 합니다. - 자연스러운 끝이 있는 것이라면
loop={false}를 생각해 보세요. 멈추지 않는 릴은 누군가 읽고 있는 페이지 구석의 움직임입니다.
- 플랫폼에서 애니메이션이 꺼져 있으면(
MediaQuery.disableAnimations) 줄은 여전히 바뀌지만 미끄러지지는 않습니다. 나가는 줄은 애니메이션 없이 사라집니다. 릴 자체가 내용이므로, 통째로 끄면 첫 줄만 남습니다. - 읽는 사람이 반드시 봐야 하는 내용에는 쓰지 마세요. 한 줄이 떠 있는 2초 동안 누가 보고 있으리라는 보장이 없고, 스크린리더는 묶음이 아니라 마침 떠 있는 줄을 받습니다.
- 모든 줄은 첫 프레임부터 트리에 있고, 떠 있지 않은 줄은 레이아웃에서 빠지는 대신 불투명도 0으로 그려집니다. 상자가 크기를 바꾸지 않는 이유입니다.
- 자연스러운 끝이 있는 것이라면
loop: false를 생각해 보세요. 멈추지 않는 릴은 누군가 읽고 있는 화면 구석의 움직임입니다.
React 빌드와 다른 점
| React | Flutter | 이유 |
|---|---|---|
| 모든 줄이 하나의 그리드 칸에 | Stack | 여러 개를 같은 자리에 두는 프레임워크 자신의 방법입니다. stack은 가장 큰 자식만큼 크고, 그것이 이 효과에 필요한 성질입니다. |
떠 있지 않은 줄이 visibility로 자리를 지킴 | 불투명도 0으로 그림 | 결과는 같습니다. 어차피 stack 안에서 겹쳐 있으니 애초에 레이아웃에서 빠질 것이 없습니다. |
rise가 CSS 길이 | double?, null이 줄 하나의 높이 | 줄 자기 높이에 대한 비율은 FractionalTranslation이 이미 뜻하는 것입니다. |
render | — | Flutter에는 다형적 요소가 없습니다. |
duration, delay가 밀리초 | Duration | 프레임워크에 이미 타입이 있습니다. |
easing이 CSS 문자열 | curve, Curve | 같은 것에 대한 Dart 자신의 이름입니다. |
repeat: number | 'infinite' | int?, null이 멈추지 않음 | 적을 'infinite'가 없고, -1은 caller가 찾아봐야 하는 sentinel입니다. |
trigger="visible"이 IntersectionObserver | 가장 가까운 Scrollable을 봅니다 | 여기에는 observer가 없습니다. 위에 scrollable이 없으면 볼 것이 없으므로 그냥 돕니다. |
prefers-reduced-motion | MediaQuery.disableAnimations | 플랫폼 자신의 신호입니다. |
className, style | — | 통과시킬 class 목록도 style 속성도 없습니다. |