Flutterでスライドの資料を作ってみた(flutter_deck)
はじめに
この記事は私の作業履歴となっているため、まとまったものが読みたい方はこちらを参照してください。
未執筆
環境
- OS:MacOS Sonoma 14.5
- Flutter 3.19.4
- Dart 3.3.2
使用するパッケージ
flutter pub add flutter_deck:^0.14.0
私の環境だと^0.15.0
は起動時にエラーが発生しました。
追加で入れたパッケージ
- build_runner
- flutter_gen_runner
導入
main.dartは一旦はこんな感じになりました。
とりあえず背景色とspeakInfo
とslideSize
設定してみました。slides
にはスライドのウィジェットを入れるぽいです。
import 'package:flutter/material.dart';
import 'package:flutter_deck/flutter_deck.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return FlutterDeckApp(
speakerInfo: FlutterDeckSpeakerInfo(
name: 'Hibana',
description: 'エンジニア',
socialHandle: '@r5437198',
imagePath: Assets.me.path,
),
configuration: FlutterDeckConfiguration(
background: const FlutterDeckBackgroundConfiguration(
light: FlutterDeckBackground.solid(
Color(0xFFFFFFFF),
),
dark: FlutterDeckBackground.solid(
Color(0xFF192638),
),
),
slideSize: FlutterDeckSlideSize.fromAspectRatio(
aspectRatio: const FlutterDeckAspectRatio.ratio16x10(),
),
),
slides: [],
);
}
}
つくってみる
今回はゴリラについてのスライドを作りたいと思います。ゴリラの理由は特にないです。
ざっくり作る内容です。(所々、スライドの作成工程は省略します)
- タイトル
- 目次
- なぜゴリラ?
- ゴリラについて
- ゴリラを取り巻く問題
- まとめ
タイトルスライド(FlutterDeckSlide.blank)
スライドにはまずタイトルのスライドが必要ですね。
基本的にFlutterDeckはFlutterDeckSlideWidget
を継承して、記載するみたいです。
import 'package:flutter/material.dart';
import 'package:flutter_deck/flutter_deck.dart';
class TitleSlide extends FlutterDeckSlideWidget {
TitleSlide()
: super(
configuration: const FlutterDeckSlideConfiguration(
route: '/title',
title: 'ゴリラについて',
footer: FlutterDeckFooterConfiguration(
showFooter: false,
),
),
);
FlutterDeckSlide build(BuildContext context) {
return FlutterDeckSlide.title(
title: 'ゴリラについて',
);
}
}
文字が小さいですね。カスタムしてタイトルスライドを作りたい場合はFlutterDeckSlide.blank
を使ったほうがいいみたいです。
- return FlutterDeckSlide.title(
- title: 'ゴリラについて',
- );
+ return FlutterDeckSlide.blank(
+ builder: (context) => Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 120,
+ ),
+ child: Row(
+ children: [
+ Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Text(
+ 'ゴリラについて',
+ style: TextStyle(
+ fontSize: 88,
+ ),
+ ),
+ FlutterDeckSpeakerInfoWidget(
+ speakerInfo: FlutterDeckSpeakerInfo(
+ name: 'Hibana',
+ description: 'エンジニア',
+ socialHandle: '@r5437198',
+ imagePath: Assets.me.path,
+ ),
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ );
今度は逆に文字が大きいかも、まあいいか。
目次スライド(FlutterDeckSlide.template)
目次はこんな感じになりました。
import 'package:flutter/material.dart';
import 'package:flutter_deck/flutter_deck.dart';
class TemplateSlide extends FlutterDeckSlideWidget {
TemplateSlide({
required this.route,
required this.title,
this.steps = 1,
required this.child,
}) : super(
configuration: FlutterDeckSlideConfiguration(
route: route,
steps: steps,
header: FlutterDeckHeaderConfiguration(
title: title,
),
),
);
final String route;
final String title;
final int steps;
final Widget child;
FlutterDeckSlide build(BuildContext context) {
return FlutterDeckSlide.template(
headerBuilder: (context) => FlutterDeckHeader(title: title),
contentBuilder: (context) => Padding(
padding: const EdgeInsets.symmetric(
// NOTE: FlutterDeckSlide.blankのデフォルトサイドパディング16と合わせた
horizontal: 16 + 120,
vertical: 60,
),
child: child,
),
);
}
}
import 'package:flutter/cupertino.dart';
import 'package:try_flutter_deck/slides/template.dart';
class IndexSlide extends TemplateSlide {
IndexSlide()
: super(
route: '/index',
title: '目次',
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: 60,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'・なぜゴリラ?',
style: TextStyle(
fontSize: 96,
),
),
Text(
'・ゴリラについて',
style: TextStyle(
fontSize: 96,
),
),
Text(
'・ゴリラを取り巻く問題',
style: TextStyle(
fontSize: 96,
),
),
Text(
'・まとめ',
style: TextStyle(
fontSize: 96,
),
),
],
),
),
],
),
);
}
目次書きながら最近人前で話してないなーと思ったり
目的スライド(FlutterDeckSlideStepsBuilder)
FlutterDeckSlideConfiguration
のsteps
に記載した回数、FlutterDeckSlideStepsBuilder
で変化させることができます。
ページ送りすると、URLは以下のように変わります。
http://localhost/#/purpose?step=2 -> http://localhost/#/purpose?step=3
コードで見た方が分かりやすいと思います。
import 'package:flutter/material.dart';
import 'package:flutter_deck/flutter_deck.dart';
import 'package:try_flutter_deck/slides/template.dart';
class PurposeSlide extends TemplateSlide {
PurposeSlide()
: super(
route: '/purpose',
title: '目的',
steps: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 60,
),
child: FlutterDeckSlideStepsBuilder(
builder: (BuildContext _, int step) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: _getTextList().getRange(0, step).toList(),
),
),
),
],
),
);
static List<Widget> _getTextList() => const [
Center(
child: Text(
'皆さん、しりとりで必ず「ゴリラ」使いますよね?',
style: TextStyle(
fontSize: 80,
),
),
),
Center(
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 72,
),
child: Icon(
Icons.arrow_downward,
size: 96,
),
),
),
Center(
child: Text(
'ゴリラについて詳しくなりましょう!',
style: TextStyle(
fontSize: 80,
color: Colors.amber,
),
),
),
];
}
初期表示だと 皆さん、しりとりで必ず「ゴリラ」使いますよね?
のみ表示されています。ページ送りするごとに矢印
、ゴリラについて詳しくなりましょう!
が表示されます。
ゴリラについてスライド(FlutterDeckSlide.split)
import 'package:flutter/material.dart';
import 'package:flutter_deck/flutter_deck.dart';
import 'package:try_flutter_deck/gen/assets.gen.dart';
class AboutGorillaSlide extends FlutterDeckSlideWidget {
AboutGorillaSlide()
: super(
configuration: const FlutterDeckSlideConfiguration(
route: '/about-gorilla',
header: FlutterDeckHeaderConfiguration(
title: 'ゴリラについて',
),
),
);
FlutterDeckSlide build(BuildContext context) {
return FlutterDeckSlide.split(
theme: FlutterDeckTheme.of(context).copyWith(
splitSlideTheme: const FlutterDeckSplitSlideThemeData(
rightBackgroundColor: Color(0xFF192638),
leftBackgroundColor: Color(0xFF192638),
),
),
leftBuilder: (context) => const Padding(
padding: EdgeInsets.only(
left: 120,
top: 120,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'日本の動物園にいるのは全てこのゴリラ',
style: TextStyle(
fontSize: 64,
color: Colors.amber,
),
),
Divider(height: 96, thickness: 4),
Text(
'生息地:中央アフリカ、カメルーンなど',
style: TextStyle(
fontSize: 64,
),
),
Text(
'体重:100〜200kg',
style: TextStyle(
fontSize: 64,
),
),
Text(
'性格:繊細、ストレスで体調を崩しやすい',
style: TextStyle(
fontSize: 64,
),
),
],
),
),
rightBuilder: (context) => Column(
children: [
const SizedBox(height: 120 + 16),
Assets.gorilla.image(),
const SizedBox(height: 8),
const Text(
'ニシローランドゴリラ',
style: TextStyle(
fontSize: 56,
),
),
],
),
);
}
}
再配布可能なゴリラのフリー画像が見つけられなかったため、ダミー画像になっています。
ゴリラについてのスライド2(FlutterDeckSlide.bigFact)
import 'package:flutter/material.dart';
import 'package:flutter_deck/flutter_deck.dart';
class AboutGorillaNameSlide extends FlutterDeckSlideWidget {
const AboutGorillaNameSlide()
: super(
configuration: const FlutterDeckSlideConfiguration(
route: '/about-gorilla/name',
header: FlutterDeckHeaderConfiguration(
title: 'ゴリラについて',
),
),
);
FlutterDeckSlide build(BuildContext context) {
return FlutterDeckSlide.bigFact(
title: 'ゴリラ=ゴリラ=ゴリラ',
subtitle: 'ゴリラ科ゴリラ属ゴリラ種という意味',
theme: FlutterDeckTheme.of(context).copyWith(
bigFactSlideTheme: const FlutterDeckBigFactSlideThemeData(
titleTextStyle: TextStyle(color: Colors.amber),
),
),
);
}
}
完成した全てのスライド
スライド
感想
スライドをコードで保管したい人やFlutterに慣れている人はFlutterDeckを使用してみてもいいんじゃないかと思いました。また、これが一番強みであると思ってて(今回は使用してないですが)、Flutterなのでボタン等もスライド上でちゃんと動きます。FirebaseRemoteConfigを使用すれば、アプリケーションごとスライドに埋め込むことができるぽいです。
今回のコード
Discussion