2021/5/21 : Flutter : Extract Flutter Widgetを使おう

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がありますのでそれについてはこちらをご覧ください

コメントを残す

メールアドレスが公開されることはありません。