こんにちは!mukaigaです。可茂IT塾でお世話になりはじめてはや4ヶ月が過ぎようとしています。
スゴすぎる先輩エンジニア達にはいつ追いつけるのでしょうか・・・。
さて今回は、riverpodのサンプルアプリのようなものを作ってきたのでご紹介します!
この記事で分からないことなどがあれば、ぜひ自分のTwitterのDMにてご質問下さい!
Mukaiga Twitter : https://twitter.com/MukaigawaraYuki
Containerを動的に操作できるアプリ
flutter-web
flutter_riverpod: ^1.0.3
まずはこうゆうアプリを作ろうとした時に、どう作るかをさーっと考えます。
変更した'width'などの値に対応して、Widgetを変化させていますよね。
「んー?アニメーションが必要ー?」
「StatefulWidgetであーだこーだするんでしょ!」
恐らくriverpodを使わないなら、StatefulWidgetでWidgetに状態を持たせるのが良いでしょう。
では一度、StatefulWidgetで作ってみます。
もし良かったら、一回自分で作ってみて、後からコードを見てもらうと良いかもしれません!
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'ContainerTester',
theme: ThemeData(primarySwatch: Colors.red),
debugShowCheckedModeBanner: false,
home: const MyWidget(),
);
}
}
/// ここからStatefulWidgetにしちゃうよ!
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
/// widthの変数を宣言 widthはdouble型だよ!
double _containerWidth = 100.0;
/// リセット用の既定値
final double _defaultWidth = 100.0;
late String _labelText = _containerWidth.toString();
final String _defaultText = "100.0";
Widget build(BuildContext context) {
/// 画面の大きさを取得する
final Size _size = MediaQuery.of(context).size;
return Scaffold(
/// リセットボタン
floatingActionButton: FloatingActionButton(
onPressed: () {
/// 代入し直してsetStateで更新
_containerWidth = _defaultWidth;
_labelText = _defaultText;
setState(() {});
},
child: const Icon(Icons.settings_backup_restore),
),
body: Column(
children: [
SizedBox(
/// 画面の大きさの半分
height: _size.height * 0.5,
child: Center(
/// 動かす対象「今回の主役」!
child: Container(
width: _containerWidth,
height: 100,
color: Colors.red,
),
),
),
const Divider(),
Column(
children: [
Row(
children: [
const SizedBox(
width: 100,
child: Center(
widthFactor: 100,
child: Text("width"),
),
),
SizedBox(
width: 150,
child: Center(child: Text(_labelText)),
),
SizedBox(
width: 300,
child: Slider(
value: _containerWidth,
min: 1,
max: 400,
onChanged: (double value) {
_containerWidth = value;
_labelText = value.toString();
/// setStateでUIを更新!
setState(() {});
}),
),
],
),
],
),
],
),
);
}
}
なんか段々こじつけみたいになって来たので、これくらいに・・・
まずはmain.dartから!
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_web_uisite/UI/Parts/width_area.dart';
/// MyAppをProviderScopeで包む!
void main() => runApp(const ProviderScope(child: MyApp()));
/// Providerを作る!初期値で100.0を与えてるよ!
final widthProvider = StateProvider((ref) => 100.0);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'ContainerTester',
theme: ThemeData(primarySwatch: Colors.red),
debugShowCheckedModeBanner: false,
home: const MyWidget(),
);
}
}
/// StatefulWidgetをConsumerWidgetに
class MyWidget extends ConsumerWidget {
const MyWidget({Key? key}) : super(key: key);
/// 要注意!ConsumerWidgetのbuildのコンストラクタにはWidgetRef型が必要!
Widget build(BuildContext context, WidgetRef ref) {
/// ここで作ったwidthProviderを読んでるよ!
double _width = ref.watch(widthProvider.state).state;
final Size _size = MediaQuery.of(context).size;
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
/// ref.refreshでリソースをリセット!
ref.refresh(widthProvider);
},
child: const Icon(Icons.settings_backup_restore),
),
body: Column(
children: [
SizedBox(
height: _size.height * 0.5,
child: Center(
/// 滑らかにするためにAnimatedContainerに!
child: AnimatedContainer(
duration: const Duration(microseconds: 100000),
width: _width,
height: 100,
color: Colors.red,
),
),
),
const Divider(),
Column(
children: const [
/// 別ページに移したよ!
WidthArea(),
],
),
],
),
);
}
}
特に大事なのは
double _width = ref.watch(widthProvider.state).state;
ここで、ref.watchで自分の作ったProvider(widthProvider)を参照しているところです!
.watchは「更新を検知」=「値が変えられた時」に、自動で値を入れ直してくれるということです!
つまり、この文の意味は「double _width = widthProviderの値が更新された時に自動で値を入れる」みたいな感じです!
勝手に更新してくれるので、StatefulWidgetでUIを更新するために書いてた、SetStateメソッドは書く必要がないのです!
あともう一つ。リセットボタンの処理にて。
ref.refresh(widthProvider);
ここで、widthProviderを「.refresh」していますよね。
これは、今widthProviderが管理している値をその名の通りリフレッシュ!してくれます。
つまり、最初にwidthProviderに入れた値、100.0に戻してくれるのです。
これを書くだけでリセット処理が書けてしましました。楽ちんだし、綺麗!
(main.dartではなく、width_area.dartに書いています)
まずはコード!
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_web_uisite/main.dart';
class WidthArea extends ConsumerWidget {
const WidthArea({Key? key}) : super(key: key);
Widget build(BuildContext context, WidgetRef ref) {
final _width = ref.watch(widthProvider.state).state;
return Row(
children: [
const SizedBox(
width: 100,
child: Center(
child: Text("width"),
),
),
SizedBox(
width: 100,
child: Center(child: Text(_width.roundToDouble().toString())),
),
SizedBox(
width: 500,
child: Slider(
value: _width,
min: 1,
max: 400,
onChanged: (double value) {
ref.read(widthProvider.state).state = value;
}),
),
],
);
}
}
さて、まずはここ!
final _width = ref.watch(widthProvider.state).state;
普通なら値を子Widgetに渡したり、ごちゃごちゃしなければいけません。
しかし、riverpodを使えばこのように他のファイルからでも簡単に値の管理ができるようになります!
onChanged: (double value) {
ref.read(widthProvider.state).state = value;
}),
次に大事なのはここでしょう!さっきまでは、値を読み取るだけでした。
ここでしたいのは、値を書き換えることです!
ここではref.readを使っていきましょう!上の通りに書くだけです・・・。
これだけでwidthProviderの値にvalue(Sliderからの値)が入ります。
今回はwidthしかいじれるようにしていませんが、heightやcolorなども変えられたら面白いですよね。
全てのプロパティ変えられたら、Containerをwebで簡単に確認できるツールができるのでは!? 使わないと思いますが
riverpodについてもっと詳しく!という方は是非
可茂IT塾 > ブログ > riverpodタグ から記事をご覧ください!
可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More