どうもFlutter超初心者です(挨拶
久しぶりにFlutterに触れてみたので書いてみる。
あいも変わらずViewの作り方が全くわかってない。。。
で、タイトル。
FlutterってViewの更新をするのにStatefulWidget使って更新する。
ただこいつの何が行けないってStatefulWidget の子View?の1つだけの更新を行うっていうことが出来ないらしい(多分
StatefulWidgetを更新しようとすると子Viewが全てRebuild掛かっちゃって描画に時間かかるらしい。らしい。
詳しいことはちゃんとは調べてないw
Viewの作り方また全然把握してないしね。
というわけで実験。
サンプルのFlutterProjectおなじみの少しだけ改良追加した版。
サンプルのカウンターを3つにしたコード
//
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter1 = 0;
int _counter2 = 0;
int _counter3 = 0;
void _incrementCounter1() {
setState(() {
_counter1++;
});
}
void _incrementCounter2() {
setState(() {
_counter2++;
});
}
void _incrementCounter3() {
setState(() {
_counter3++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'$_counter1',
style: Theme.of(context).textTheme.display1,
),
Text(
'$_counter2',
style: Theme.of(context).textTheme.display1,
),
Text(
'$_counter3',
style: Theme.of(context).textTheme.display1,
),
MaterialButton(
minWidth: 160,
onPressed: () {
_incrementCounter1();
},
child: Text("カウント1アップ"),
),
MaterialButton(
minWidth: 160,
onPressed: () {
_incrementCounter2();
},
child: Text("カウント2アップ"),
),
MaterialButton(
minWidth: 160,
onPressed: () {
_incrementCounter3();
},
child: Text("カウント3アップ"),
)
],
),
),
);
}
}
カウント用のテキストを3つ、各テキストをカウントアップするためのボタン3つって言う簡単なコード。
このどれかのボタンを押すと、、、。
ちょっと分かりづらいけど、全てのWidgetがrebuildされている。
Viewの更新処理が無駄に走って重いってことね。
どう対応するか・・・。
Flutterって○○パターンっていう実装がとっても多い印象だけど、これから書くのは多分Providerパターン(多分
Providerパターンで書き直す
Package
provider: ^4.0.4
コード
//
class HogeViewModel with ChangeNotifier {
int _counter1 = 0;
int _counter2 = 0;
int _counter3 = 0;
void incrementCounter1() {
_counter1++;
notifyListeners();
}
void incrementCounter2() {
_counter2++;
notifyListeners();
}
void incrementCounter3() {
_counter3++;
notifyListeners();
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<HogeViewModel>(
create: (_) => HogeViewModel(),
child: Scaffold(
appBar: AppBar(title: Text(title)), body: MyHomePageView()));
}
}
class MyHomePageView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final model = Provider.of<HogeViewModel>(context, listen: false);
return content(context, model);
}
Widget content(BuildContext context, HogeViewModel model) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Selector<HogeViewModel, int>(
selector: (context, model) => model._counter1,
builder: (context, counter, child) => Text(
'$counter',
style: Theme.of(context).textTheme.display1,
),
),
Selector<HogeViewModel, int>(
selector: (context, model) => model._counter2,
builder: (context, counter, child) => Text(
'$counter',
style: Theme.of(context).textTheme.display1,
),
),
Selector<HogeViewModel, int>(
selector: (context, model) => model._counter3,
builder: (context, counter, child) => Text(
'$counter',
style: Theme.of(context).textTheme.display1,
),
),
MaterialButton(
minWidth: 160,
onPressed: () {
model.incrementCounter1();
},
child: Text("カウント1アップ"),
),
MaterialButton(
minWidth: 160,
onPressed: () {
model.incrementCounter2();
},
child: Text("カウント2アップ"),
),
MaterialButton(
minWidth: 160,
onPressed: () {
model.incrementCounter3();
},
child: Text("カウント3アップ"),
)
],
),
);
}
}
ChangeNotifierがProviderで使えるやつ。
Andoridで言うと個人的にはViewModelかなって思う。
で、内部で持っている変数がLiveData。
View側でSelectorっていうWidgetで子に作りたいViewのWidgetを置く。
ChangeNotifier内部の変数の値が変わったことをnotifyListeners()で通知すると、値が変わった変数のSelectorだけ動いてくれるって感じ。
頭ではなんとなく理解したけど、文字に起こすのは難しい\(^o^)/
こんな感じにRebuildされている。
Selectorまでは通知が来て動いてしまってるけど、Selectorの子ViewまでにはRebuildの更新が来ていないことがわかる。
多分、処理が軽くなる!多分!
このサンプルだとViewの数が少ないから体感出来ていないけど、大きめのViewがたくさんあるのは体感できるはず!
で、ChangeNotifier-Selectorの何が良いってAndoroid開発者ならViewModel-LiveDataを最近はみんな使ってると思うんだけど、ほぼほぼ同じ感覚で使えるってこと。
欲しい値の変更受け取ってView更新。使いやすい!理解しやすい!
BLocパターンとか意味分かんないもん(ぇ
・・・・。
これからもまったーーーりとFlutterに触れていきますよ!