null-safety-article
(1)まずシンプルな例から。
//(1)Extract前(簡単バージョン) import 'package:flutter/material.dart'; void main(){ runApp(MaterialApp(home:MyApp(),),); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar:AppBar(title:const Text('title'),), body: Container( color:Colors.green, child:Column( children:const [ Card( child:Text("first card"), ), Card( child:Text("second card"), ), ], ), ), ); } }
特に何もない普通のサンプルなんですが、Column以下を[Extract Flutter Widget]を使って抜き出します。
抜き出したいColumnにカーソルを合わせて右クリック>>[Refactor]>>[Extract Flutter Widget]を選択します。
抜き出すWidgetのクラス名を求められますので入力します。この例ではNewWidgetと入力しました。
//サンプル(1)Extract後 import 'package:flutter/material.dart'; void main(){ runApp(MaterialApp(home:MyApp(),),); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar:AppBar(title:const Text('title'),), body: Container( color:Colors.green, child:const NewWidget(), ), ); } } class NewWidget extends StatelessWidget { const NewWidget({ Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return Column( children:const [ Card( child:Text("first card"), ), Card( child:Text("second card"), ), ], ); } }
自動的に新しいウィジェットNewWidgetを定義してくれました。
(2)フィールド有りバージョン
//サンプル(2)Extract前(フィールド有りバージョン) import 'package:flutter/material.dart'; void main() { runApp( MaterialApp( home: MyApp(), ), ); } class MyApp extends StatelessWidget { final String title1 = "first card"; final String title2 = "second card"; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("title"), ), body: Container( color: Colors.green, child: Column( children: [ Card( child: Text(title1), ), Card( child: Text(title2), ), ], ), ), ); } }
MyAppウィジェットがフィールドtitle1,title2を持ち、Cardウィジェットでそのフィールドの値が使われています。画面表示自体はサンプル1と同じです。
サンプル1と同様にColumn以下をExtract Flutter Widgetで抜き出します。
↓
//サンプル(2)Extract後(フィールド有りバージョン) import 'package:flutter/material.dart'; void main() { runApp( MaterialApp( home: MyApp(), ), ); } class MyApp extends StatelessWidget { final String title1 = "first card"; final String title2 = "second card"; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("title"), ), body: Container( color: Colors.green, //↓アーギュメントにMyAppのフィールドを渡すようにしてくれる。 child: NewWidget(title1: title1, title2: title2), ), ); } } class NewWidget extends StatelessWidget { const NewWidget({ Key? key, required this.title1, required this.title2, }) : super(key: key); //↓自動的にフィールドを用意してくれており、コンストラクタにも //パラメータを用意してくれている。 final String title1; final String title2; @override Widget build(BuildContext context) { return Column( children: [ Card( child: Text(title1), ), Card( child: Text(title2), ), ], ); } }
自動的にNewWidgetにフィールドtitle1,title2を用意してくれました。素晴らしいですね。はい。
(3)メソッド有りバージョン
//サンプル(3)メソッド有りバージョンExtract前(エラーが出る。) import 'package:flutter/material.dart'; void main() { runApp( MaterialApp( home: MyApp(), ), ); } class MyApp extends StatelessWidget { final String title1 = "first card"; final String title2 = "second card"; String title3() { return "third card"; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text( "title", ), ), body: Container( color: Colors.green, child: Column( children: [ Card( child: Text(title1), ), Card( child: Text(title2), ), Card( child: Text(title3()), ), ], ), ), ); } }
MyAppウィジェットがメソッドtitle3を持っています。
三つ目のCardでメソッドtitle3の返り値が使われています。
同様にColumn以下をExtract Flutter Widgetで抜き出してみます。
抜き出せません。Android Studioの挙動が安定してないからか、何度かやるとサンプル(1),(2)と同じように自動的にNewWidgetの宣言コードを出せた(抜き出せた)時もありました。がエラーが出ました↓。
上記コードは自分で書きましたが、結局MyAppのメンバメソッドのtitle3を、抜き出したNewWidgetクラス内から参照することはできませんので、三つ目のCardでコンパイルエラーが発生しています。
エラー内容 The method 'title3' isn't defined for the type 'NewWidget'. メソッドtitle3がNewWidgetに定義されていません。 Try correcting the name to the name of an existing method, or defining a method named 'title3'.
エラーを修正するために、以下のようにtitle3メソッドをパラメータとしてNewWidgetが保持するようにしましょう↓。
//サンプル(3)メソッド有りバージョンExtract後(エラーを修正。) import 'package:flutter/material.dart'; void main() { runApp( MaterialApp( home: MyApp(), ), ); } class MyApp extends StatelessWidget { final String title1 = "first card"; final String title2 = "second card"; String title3() { return "third card"; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text( "title", ), ), body: Container( color: Colors.green, child: NewWidget( title1: title1, title2: title2, title3: title3, ), ), ); } } class NewWidget extends StatelessWidget { const NewWidget({ Key? key, required this.title1, required this.title2, required this.title3}) : super(key: key); final String title1; final String title2; final String Function() title3; @override Widget build(BuildContext context) { return Column( children: [ Card( child: Text(title1), ), Card( child: Text(title2), ), Card( child: Text(title3()), ), ], ); } }
こうすればエラーは消えて、実行できるようになりますが、ここまではExtract Flutter Widgetではやってくれないようです(現時点では)。
なのでメソッドを渡すコードは自分で書く必要があります。
以上です。
あと似た機能としてExtract Methodがありますのでそれについてはこちらをご覧ください。