대부분 앱들을 설치하고 최초 실행 시,
튜토리얼이 진행된다.
개발자가 만드는 서비스가 아무리 쉽고 간단해도
아주 간단한 튜토리얼은 필요하다.
이번엔 이 라이브러리들을 사용해볼 예정이다.
shared_preferences
https://pub.dev/packages/shared_preferences
shared_preferences | Flutter package
Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.
pub.dev
shared_preferences | Flutter package
Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.
pub.dev
shared_preference는 로컬 저장소 라이브러리다.
앱 내 로컬 스토리지에 키-값 형태로 데이터를 저장하고
필요 시, 앱에 저장된 데이터를 불러올 수 있다.
튜토리얼을 본 적 없다면 진행 후,
토글값을 바꿔 더 이상 튜토리얼 화면이 안 나오도록 할 수 있다.
introduction_screen
https://pub.dev/packages/introduction_screen
introduction_screen | Flutter package
Introduction/Onboarding package for flutter app with some customizations possibilities
pub.dev
튜토리얼 화면을 만들기 귀찮을 때 쓰는 라이브러리다.
과정
shared_preferences를 쓰기 위한 사전 설정이 필요하다.
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import './features/my_app.dart';
import './features/tutorial/tutorial_screen.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
final bool hasSeenOnboarding = prefs.getBool('isTutorial') ?? false;
runApp(ProviderScope(
child: MaterialApp(
home: hasSeenOnboarding? MyApp() : TutorialScreen(),
debugShowCheckedModeBanner: false,
),
));
}
riverpod 연습 때문에 ProviderScope를 썼는데
그게 아니면 굳이 쓸 필요 없다.
다음은 MyApp을 구성한다.
// lib/my_app.dart
import 'package:flutter/material.dart';
import '../utils/route_manager.dart';
import './tutorial/tutorial_screen.dart';
class MyApp extends StatelessWidget{
const MyApp({
super.key,
});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: buildColumn(context),
),
);
}
// 위젯을 빌드에 필요한 context를
Widget buildColumn(BuildContext context){
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
buildElevatedButton(context, TutorialScreen(), "tutorial example"),
],
);
}
Widget buildElevatedButton(BuildContext context, Widget target, String buttonName){
return Container(
margin: EdgeInsets.all(15),
child: ElevatedButton(
onPressed: () {
RouteManager.moveTo(context, () => target);
},
child: Text("${buttonName}")
),
);
}
}
RouteManager는 Navigator를 편하게 쓰려고 만들었다.
import 'package:flutter/material.dart';
class RouteManager {
static void moveTo(
BuildContext context,
Widget Function() targetBuilder, {
bool fullscreenDialog = false,
}) {
// future: 조건 확인, 로그, 애니메이션 등 가능
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => targetBuilder(),
fullscreenDialog: fullscreenDialog
)
);
}
}
복잡한 설정 할 필요 없이
위젯을 구성하는 핸들러와 화면전환할 위젯만 넘겨주면 된다.
나머지는 위 함수에서 알아서 동작한다.
tutorial_screen
// tutorial_screen.dart
import 'package:flutter/material.dart';
import 'package:introduction_screen/introduction_screen.dart';
import 'package:riverpod_practice/utils/route_manager.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../my_app.dart';
import '../../utils/route_manager.dart';
/// 튜토리얼 화면 예제
/// 필요한 라이브러리 : shared_preferences, introduction_screen
/// shared_preferences로 튜토리얼 완료 여부 값을 앱 내 로컬 저장소에 저장하고
/// 더 이상 튜토리얼이 안 나오도록 처리 가능
class TutorialScreen extends StatelessWidget{
ScrollController scrollController = ScrollController();
TutorialScreen({super.key});
@override
Widget build(BuildContext context) {
return IntroductionScreen(
pages: [
buildFirstViewModel(),
buildSecondViewModel(),
buildThirdViewModel()
],
onDone: () => complete(context),
onSkip: () => complete(context),
showSkipButton: true,
skip: buildText(value: "skip", fontSize: 18.0),
next: buildText(value: "Next", fontSize: 18.0),
done: buildText(value: "Done", fontSize: 18.0),
);
}
void complete(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isTutorial', true);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => MyApp()
)
);
}
PageViewModel buildFirstViewModel(){
return PageViewModel(
useScrollView: false,
title: "",
bodyWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
buildText(value: "테스트입니다", fontSize: 25),
buildText(value: "간단한 튜토리얼 화면입니다.", fontSize: 18),
Image.asset("assets/test34.png")
],
),
);
}
PageViewModel buildSecondViewModel(){
return PageViewModel(
useScrollView: false,
title: "",
bodyWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
buildText(value: "환영합니다"),
buildText(value: "두번째 화면이에요!"),
Image.asset("assets/test34.png")
],
),
);
}
PageViewModel buildThirdViewModel(){
return PageViewModel(
useScrollView: false,
title: "",
bodyWidget: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
buildText(value: "마지막이에요"),
buildText(value: "이제 예제는 끝났습니다"),
Image.asset("assets/test34.png")
],
),
);
}
}
실행결과
매우 간단하게 구현할 수 있다.
'flutter' 카테고리의 다른 글
Flutter Navigator 사용법 (0) | 2024.12.11 |
---|---|
Flutter Toast 사용법 (0) | 2023.05.24 |
Flutter TabBar 사용법 (0) | 2023.05.23 |