Flutter로 일정 시간 후에 애니메이션 시작
12196 단어 Flutter_HooksRiverpodFlutter
만든 애니메이션
Flutter Web에서 스플래툰 2 플레이어용 동영상 플레이어 앱을 만들었습니다. 이 응용 프로그램은 커서 키의 좌우 또는 이미지 인식으로 추출된 장면의 시간 클릭으로 재생 위치를 점프 할 수 있습니다. 그 때 동영상 위로 점프처 시각을 컷 인 표시한 후, 0.7초 후에 0.3초에 걸쳐 페이드 아웃합니다.
※ 동영상 플레이어내에 표시되고 있는 동영상은 닌텐도 주식회사의 스플라툰 2로부터의 인용입니다.
만드는 법
Flutter에서 페이드 아웃과 같은 애니메이션을 수행하는 방법에는 Animated와 함께 Widget을 사용하는 방법이 있습니다. 페이드 아웃의 경우 AnimatedOpacity 클래스를 사용합니다. 그러나 그것만으로는 「0.7초 후에 애니메이션을 시작한다」라고 하는 설정을 할 수 없고, 타이머 클래스와 조합해 사용했습니다. 순서를 하나씩 해설합니다.
전제
앱은 다음 패키지를 사용하여 구축하고 있습니다.
Flutter에서 페이드 아웃과 같은 애니메이션을 수행하는 방법에는 Animated와 함께 Widget을 사용하는 방법이 있습니다. 페이드 아웃의 경우 AnimatedOpacity 클래스를 사용합니다. 그러나 그것만으로는 「0.7초 후에 애니메이션을 시작한다」라고 하는 설정을 할 수 없고, 타이머 클래스와 조합해 사용했습니다. 순서를 하나씩 해설합니다.
전제
앱은 다음 패키지를 사용하여 구축하고 있습니다.
시간 표시 상태를 나타내는 클래스 만들기
video_time.dart
@freezed
abstract class VideoTime with _$VideoTime {
/// [currentTime] ジャンプ先時刻
/// [visible] 表示フラグ
/// [fadeOut] フェードアウトフラグ
factory VideoTime(double currentTime, bool visible, bool fadeOut) = _VideoTime;
}
시간 표시의 상태를 변경하는 StateNotifier와 그 Provider를 작성합니다.
video_time_state_notifier_provider.dart
class VideoTimeStateNotifier extends StateNotifier<VideoTime> {
VideoTimeStateNotifier() : super(VideoTime(0.0, false, false));
/// 表示時刻を更新する
/// [currentTime] 表示時刻
void setTime(double currentTime) {
state =
state.copyWith(currentTime: currentTime, visible: true, fadeOut: false);
}
/// フェードアウトをリクエストする
void requestFadeOut() {
state = state.copyWith(fadeOut: true);
}
}
final videoTimeStateNotifierProvider =
StateNotifierProvider((_) => VideoTimeStateNotifier());
재생 시간 변경이 발생하면 VideoTimeStateNotifier 클래스의 setTime 메서드가 호출됩니다.
시각 표시의 Widget 빌드
여기서 중요한 것은 useEffect 을 사용하는 것입니다. 그 이유는 다음 절에서 설명합니다.
video_time_builder.dart
HookBuilder makeVideoTimeBuilder() {
return HookBuilder(builder: (context) {
// 状態を取得
final videoTime = useProvider(videoTimeStateNotifierProvider.state);
// 不透明度
double opacity = 1.0;
// アニメーションのミリ秒
int ms = 0;
// フェードアウトするときは、0.3秒かけて不透明度0に向かう。
if (videoTime.fadeOut) {
opacity = 0.0;
ms = 300;
}
// 0.7後にフェードアウトをリクエスト
if (videoTime.visible && !videoTime.fadeOut) {
// 重要
useEffect(() {
Timer timer = Timer(Duration(milliseconds: 700), () {
// 0.7秒後に実行されるブロック
// フェードアウトをリクエスト
final videoTimeStateNotifier =
context.read(videoTimeStateNotifierProvider);
videoTimeStateNotifier.requestFadeOut();
});
return () {
// このウィジットが破棄されたときに呼ばれる
timer.cancel();
};
});
}
final textStyle = TextStyle(fontSize: 34, color: Colors.white);
return Visibility(
visible: videoTime.visible,
child: Center(
child: AnimatedOpacity(
opacity: opacity,
duration: Duration(milliseconds: ms),
child: Container(
decoration: ShapeDecoration(
color: Color.fromARGB(0xbb, 0, 0, 0), shape: StadiumBorder()),
padding: EdgeInsets.symmetric(vertical: 16, horizontal: 32),
child: Text(toTimeString(videoTime.currentTime), style: textStyle),
),
)),
);
});
}
useEffect를 사용하는 이유
실은 이 앱, 브라우저 가로폭에 따라 레이아웃이 다릅니다. 동영상 플레이어와는 별도로 이미지 인식으로 추출된 장면 목록이 있으며, 가로 폭이 좁을 때는 아래로, 넓을 때는 오른쪽에 배치됩니다.
그리고, 그 위젯 배치의 변경이 행해질 때, 위젯이 파기됩니다만, 파기된 후에 0.7초 후의 콜백이 실행되면, 다음과 같은 에러가 발생합니다.
Error: Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
따라서 위젯이 파기되면 타이머를 취소하여 0.7초 후 콜백이 호출되지 않도록 합니다. useEffect 에 건네주는 람다의 반환값은 파기된 타이밍에 불리는 람다가 됩니다.
감상
나는 평소 안드로이드 네이티브로 앱을 개발하고 있어, 이러한 애니메이션은 ObjectAnimator 클래스의 setStartDelay 메소드로 실시합니다만, Flutter는 방법이 다르다고 생각했습니다.
Reference
이 문제에 관하여(Flutter로 일정 시간 후에 애니메이션 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/tfandkusu/items/2b564292aa38580cb865
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(Flutter로 일정 시간 후에 애니메이션 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/tfandkusu/items/2b564292aa38580cb865텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)