Provider 패키지는 Flutter에서 데이터의 흐름을 관리하고 UI의 재구성을 효율적으로 처리할 수 있게 하는 인기 있는 상태 관리 솔루션 중 하나입니다. 이 패키지를 사용하면 데이터 모델을 위젯 트리의 다양한 위치에서 쉽게 접근하고, 소비할 수 있습니다. Provider는 리스너를 통해 데이터의 변경 사항을 감지하고, 데이터가 변경될 때마다 해당 데이터에 의존하는 위젯들을 자동으로 재구성하여 UI를 업데이트합니다.
// VideoConfig 클래스는 ChangeNotifier를 상속받아 isMuted 및 isAutoplay 상태를 관리합니다.
class VideoConfig extends ChangeNotifier {
bool isMuted = false; // 비디오 음소거 상태
bool isAutoplay = false; // 자동 재생 상태
// isMuted 상태를 토글하고 리스너들에게 상태 변경을 알립니다.
void toggleIsMuted() {
isMuted = !isMuted;
notifyListeners();
}
// isAutoplay 상태를 토글하고 리스너들에게 상태 변경을 알립니다.
void toggleAutoplay() {
isAutoplay = !isAutoplay;
notifyListeners();
}
}
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _notifications = false;
void _onNotificationsChanged(bool? newValue) {
if (newValue == null) return;
setState(() {
_notifications = newValue;
});
}
Widget build(BuildContext context) {
// ChangeNotifierProvider를 사용하여 VideoConfig 인스턴스를 제공합니다.
return ChangeNotifierProvider(
create: (context) => VideoConfig(),
child: Scaffold(
appBar: AppBar(
title: const Text('Settings'),
),
body: ListView(
children: [
// Provider.of<T>를 사용하여 VideoConfig 인스턴스에 접근하고, isMuted 상태에 따라 UI를 구성합니다.
SwitchListTile.adaptive(
value: Provider.of<VideoConfig>(context).isMuted,
onChanged: (value) => Provider.of<VideoConfig>(context, listen: false).toggleIsMuted(),
title: const Text("Auto Mute"),
subtitle: const Text("Videos muted by default."),
),
// 기타 설정 UI...
],
),
),
);
}
}
이 예제에서 ChangeNotifierProvider
는 VideoConfig
인스턴스를 앱의 상위에서 제공합니다. 이를 통해 SettingsScreen
위젯은 Provider.of<VideoConfig>(context)
를 사용하여 VideoConfig
인스턴스에 접근하고, isMuted
및 isAutoplay
상태에 따라 UI를 동적으로 구성할 수 있습니다. 상태가 변경될 때 notifyListeners()
메서드가 호출되면, Provider는 이를 자동으로 감지하여 의존하는 UI를 재구성합니다.
Provider 패키지는 Flutter 앱에서 상태 관리를 간결하고 효과적으로 수행할 수 있도록 돕습니다. 데이터의 흐름을 명확하게 관리하고, 필요한 곳에서 쉽게 데이터를 사용할 수 있게 해 줍니다.
제공된 코드 예시에서 context.read()
와 context.watch()
를 직접적으로 사용하지 않았습니다만, 이들의 사용 방법과 Consumer
, Provider
와의 관계에 대해 설명드리겠습니다. Provider
패키지는 Flutter에서 상태 관리를 용이하게 하는 여러 유틸리티와 패턴을 제공합니다. context.read<T>()
, context.watch<T>()
, Consumer<T>
, 그리고 Provider<T>
는 그 중 일부입니다.
context.watch<T>()
context.watch<T>()
메서드는 위젯이 데이터 모델 T
의 변화를 구독하게 만듭니다. T
가 변할 때마다 Flutter는 watch
를 호출한 위젯을 재빌드합니다. 이 방법은 위젯이 모델의 변화에 의존할 때 사용됩니다.
예시 코드에 context.watch<T>()
를 사용하는 부분이 있었다면, 그것은 SwitchListTile
위젯이 VideoConfig
의 isMuted
상태를 실시간으로 반영하도록 하기 위함입니다.
value: context.watch<VideoConfig>().isMuted,
context.read<T>()
context.read<T>()
메서드는 데이터 모델 T
를 읽기 위해 사용되지만, T
의 변화에 대해서는 구독하지 않습니다. 즉, T
가 변해도 read
를 사용하는 위젯은 재빌드되지 않습니다. read
는 주로 이벤트 핸들러나 Future
를 실행하는 데 사용됩니다.
예시 코드에서 onChanged
콜백 내에서 context.read<T>()
를 사용하여, 사용자가 스위치를 토글할 때 toggleIsMuted()
함수를 호출하는 데 사용될 수 있습니다.
onChanged: (value) => context.read<VideoConfig>().toggleIsMuted(),
ChangeNotifierProvider(
create: (context) => VideoConfig(),
child: MaterialApp(
// MaterialApp 구성
),
),
이 코드는 Flutter에서 비디오 포스트를 표시하고 관리하는 방법을 보여줍니다. 주요 기능으로는 비디오의 재생 및 일시 정지, 음소거 토글, 그리고 비디오와 관련된 상호작용을 위한 버튼들이 포함됩니다. Provider
패키지를 사용하여 비디오 설정(예: 음소거)의 상태를 관리하고, 해당 상태에 따라 UI를 동적으로 업데이트합니다.
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart';
import 'package:tiktok_clone/common/widgets/video_config/video_config.dart';
// ... 다른 import 구문들
class VideoPost extends StatefulWidget {
final Function onVideoFinished; // 비디오 재생 완료 시 호출될 콜백 함수
final int index; // 비디오 포스트의 인덱스
const VideoPost({super.key, required this.onVideoFinished, required this.index});
State<VideoPost> createState() => _VideoPostState();
}
class _VideoPostState extends State<VideoPost> with SingleTickerProviderStateMixin {
late final VideoPlayerController _videoPlayerController; // 비디오 재생을 위한 컨트롤러
final Duration _animationDuration = const Duration(milliseconds: 200); // 애니메이션 지속 시간
late final AnimationController _animationController; // 재생 아이콘 애니메이션을 위한 컨트롤러
bool _isPaused = false; // 비디오가 일시 정지 상태인지 여부
void initState() {
super.initState();
_initVideoPlayer(); // 비디오 플레이어 초기화
_animationController = AnimationController(
vsync: this, // 애니메이션 프레임 동기화를 위한 vsync
lowerBound: 1.0,
upperBound: 1.5,
value: 1.5,
duration: _animationDuration,
);
}
void _initVideoPlayer() async {
_videoPlayerController = VideoPlayerController.asset("assets/videos/video.mp4");
await _videoPlayerController.initialize(); // 비디오 초기화
await _videoPlayerController.setLooping(true); // 비디오를 반복 재생 설정
if (kIsWeb) {
await _videoPlayerController.setVolume(0); // 웹에서는 볼륨을 0으로 설정
}
_videoPlayerController.addListener(_onVideoChange); // 비디오 상태 변경 리스너 추가
setState(() {}); // UI 업데이트를 위해 상태 변경
}
Widget build(BuildContext context) {
return VisibilityDetector(
key: Key("${widget.index}"), // 각 비디오 포스트를 구분하기 위한 키
onVisibilityChanged: _onVisibilityChanged, // 화면에 보이는지 여부에 따라 동작을 변경
child: Stack(
children: [
Positioned.fill(
child: _videoPlayerController.value.isInitialized
? VideoPlayer(_videoPlayerController) // 비디오 플레이어 위젯
: Container(color: Colors.black), // 비디오 초기화 전 검은색 배경 표시
),
Positioned.fill(
child: GestureDetector(
onTap: _onTogglePause, // 탭 시 비디오 재생/일시 정지 토글
),
),
Positioned(
left: 20,
top: 40,
child: IconButton(
icon: FaIcon(
context.watch<VideoConfig>().isMuted
? FontAwesomeIcons.volumeOff // 음소거 상태에 따라 아이콘 변경
: FontAwesomeIcons.volumeHigh,
color: Colors.white,
),
onPressed: () {
context.read<VideoConfig>().toggleIsMuted(); // 음소거 토글 함수 호출
},
),
),
// ... 기타 UI 요소들
],
),
);
}
}
이 코드는 Provider
패키지를 사용하여 앱 전체에서 비디오 설정의 상태를 관리합니다.
비디오 포스트 위젯(VideoPost
)은 비디오를 재생하고, 음소거 상태를 토글하며, 사용자가 비디오를 탭할 때 재생 또는 일시 정지 상태를 토글하는 등의 기능을 제공합니다. VideoConfig
클래스는 비디오의 음소거(isMuted
) 상태와 자동 재생(isAutoplay
) 상태를 관리합니다. 사용자 인터페이스는 비디오 설정의 현재 상태(isMuted
, isAutoplay
)에 따라 동적으로 업데이트되며, 이는 Provider
를 통해 상태 관리가 이루어지기 때문입니다.
VisibilityDetector
를 사용하여 비디오가 화면에 완전히 보일 때만 재생하도록 하고, 화면에서 사라지면 일시 정지하도록 함으로써 사용자 경험을 개선합니다. 이러한 방식으로, 앱의 성능을 최적화하고 사용자에게 더 나은 시청 경험을 제공할 수 있습니다.