【Flutter】Firebaseの利用

firebaseのtoolkitをインストール
$ curl -sL https://firebase.tools | bash

$ flutter pub upgrade firebase_core
$ flutter pub add cloud_firestore
$ flutter pub upgrade cloud_firestore

1.firebaseで新しいプロジェクトを作成する
2.firestoreで新しいデータベースを作成する
3.コレクションの作成
name(string), mail(string), age(number)
4.firebaseの設定を行う
$ dart pub global activate flutterfire_cli
$ flutterfire configure

import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'dart:convert';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(new MyApp());
}

// 省略

  void fire() async {
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    final snapshot = await firestore.collection('mydata').get();
    var msg = '';
    snapshot.docChanges.forEach((element) {
      final name = element.doc.get('name');
      final mail = element.doc.get('mail');
      final age = element.doc.get('age');
      msg += "${name} (${age}) <${mail}>\n";
    });
    _controller.text = msg;
  }

【Flutter】ネットワークアクセス

class _MyHomePageState extends State<MyHomePage> {
  final _controller = TextEditingController();
  static const host = 'baconipsum.com';
  static const path = '/api/?type=meat-and-filler&paras=1&format=text';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20.0),
        child:Column(
          children:<Widget> [
               Text('INTERNET ACCESS',
               style: TextStyle(fontSize: 32,
               fontWeight: ui.FontWeight.w500),
               ),
              Padding(padding: EdgeInsets.all(10.0)),
              TextField(
                controller: _controller,
                style: TextStyle(fontSize: 24),
                minLines: 1,
                maxLines: 5,
              ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.open_in_new),
            onPressed: () {
              getData();
              showDialog(
                context: context,
                builder: (BuildContext context) =>
                    AlertDialog(
                      title: Text("loaded!"),
                      content: Text("get content from URI."),
                    )
              );
            }
          )
    );
  }

  void getData() async {
    var http = await HttpClient();
    HttpClientRequest request = await http.get(host, 80, path);
    HttpClientResponse response = await request.close();
    final value = await response.transform(utf8.decoder).join();
    _controller.text = value;
  }
}
  void setData() async {
    final ob = {
      "title": "foo",
      "author": "hoge",
      "content": "this is content.サンプルコンテンツ"
    };
    final jsondata = json.encode(ob);
    var https = await HttpClient();
    HttpClientRequest request = await https.postUrl(Uri.parse(url));
    request.headers.set(HttpHeaders.contentTypeHeader, "application/json; charset=UTF-8");
    request.write(jsondata);
    HttpClientResponse response = await request.close();
    final value = await response.transform(utf8.decoder).join();
    _controller.text = value;
  }

【Flutter】設定情報の利用

pubspec.yamlにShared Preferencesというパッケージを追加する必要がある

dependencies:
  flutter:
    sdk: flutter
  path_provider: any
  shared_preferences: any
class _MyHomePageState extends State<MyHomePage> {
  final _controller = TextEditingController();
  double _r = 0.0;
  double _g = 0.0;
  double _b = 0.0;

  @override
  void initState(){
    super.initState();
    loadPref();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child:Column(
          children:<Widget> [
               Text('PREFERENCES ACCESS',
               style: TextStyle(fontSize: 32,
               fontWeight: ui.FontWeight.w500),
               ),
              Padding(padding: EdgeInsets.all(10.0)),
              TextField(
                controller: _controller,
                style: TextStyle(fontSize: 24),
                minLines: 1,
                maxLines: 5,
              ),
              Padding(padding: EdgeInsets.all(10.0)),
              Slider(
                min: 0.0,
                max: 255.0,
                value: _r,
                divisions: 255,
                onChanged: (double value) {
                  setState(() {
                    _r = value;
                  });
                },
              ),
            Slider(
              min: 0.0,
              max: 255.0,
              value: _g,
              divisions: 255,
              onChanged: (double value) {
                setState(() {
                  _g = value;
                });
              },
            ),
            Slider(
              min: 0.0,
              max: 255.0,
              value: _b,
              divisions: 255,
              onChanged: (double value) {
                setState(() {
                  _b = value;
                });
              },
            ),
              Container(
                padding: EdgeInsets.all(20),
                width: 125,
                height: 125,
                color: Color.fromARGB(255, _r.toInt(), _g.toInt(), _b.toInt()),
              ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.open_in_new),
            onPressed: () {
              savePref();
              showDialog(
                context: context,
                builder: (BuildContext context) =>
                    AlertDialog(
                      title: Text("saved!"),
                      content: Text("save preferences."),
                    )
              );
            }
          )
    );
  }

  void loadPref() async {
    final prefs = await SharedPreferences.getInstance();
    setState((){
      _r = (prefs.getDouble('r') ?? 0.0);
      _g = (prefs.getDouble('g') ?? 0.0);
      _b = (prefs.getDouble('b') ?? 0.0);
      _controller.text = (prefs.getString('input') ?? '');
    });
  }

  void savePref() async {
    final prefs = await SharedPreferences.getInstance();
    prefs.setDouble('r', _r);
    prefs.setDouble('g', _g);
    prefs.setDouble('b', _b);
    prefs.setString('input', _controller.text);
  }
}

【Flutter】ファイルアクセス

import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'dart:io';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(new MyApp());
}
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Generated App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: const Color(0xFF2196f3),
        canvasColor: const Color(0xFFfafafa),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _controller = TextEditingController();
  final _fname = 'flutter_sampledata.txt';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child:Column(
          children:<Widget> [
               Text('FILE ACESS.',
               style: TextStyle(fontSize: 32,
               fontWeight: ui.FontWeight.w500),
               ),
              Padding(padding: EdgeInsets.all(10.0)),
              TextField(
                controller: _controller,
                style: TextStyle(fontSize: 24),
                minLines: 1,
                maxLines: 5,
              )
              ],
            ),
          ),
          bottomNavigationBar: BottomNavigationBar(
            backgroundColor: Colors.blue,
            selectedItemColor: Colors.white,
            unselectedItemColor: Colors.white,
            currentIndex: 0,
            items: <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                label: 'Save',
                icon: Icon(Icons.save, color: Colors.white, size: 32),
              ),
              BottomNavigationBarItem(
                label: 'Load',
                icon: Icon(Icons.open_in_new, color: Colors.white, size:32)
              ),
            ],
            onTap: (int value) async {
              switch (value) {
                case 0:
                  saveIt(_controller.text);
                  setState(() {
                    _controller.text = '';
                  });
                  showDialog(
                    context: context,
                    builder: (BuildContext context) => AlertDialog(
                      title: Text("saved!"),
                      content: Text("save message to file."),
                    )
                  );
                  break;
                case 1:
                  String value = await loadIt();
                  setState((){
                    _controller.text = value;
                  });
                  showDialog(
                    context: context,
                    builder: (BuildContext context) => AlertDialog(
                      title: Text("loaded!"),
                      content: Text("load message from file."),
                    )
                  );
                  break;
                default:
                  print('no default.');
              }
            },
          ),
    );
  }

  Future<File> getDataFile(String filename) async {
    final directory = await getApplicationDocumentsDirectory();
    return File(directory.path + '/' + filename);
  }

  void saveIt(String value) async {
    final file = await getDataFile(_fname);
    file.writeAsString(value);
  }

  Future<String> loadIt() async {
    try {
      final file = await getDataFile(_fname);
      return file.readAsString();
    } catch (e) {
      return '*** no data ***';
    }
  }
}

リソースファイルの読み込み
L assetsフォルダ内にdocumentsというフォルダを用意し、その中にdata.txtファイルを作成する
pubspec.yamlに追記

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:ui' as ui;

void main() {
  runApp(new MyApp());
}
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Generated App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: const Color(0xFF2196f3),
        canvasColor: const Color(0xFFfafafa),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _controller = TextEditingController();
  final _fname = 'documents/data.txt';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child:Column(
          children:<Widget> [
               Text('RESOURCE ACCESS',
               style: TextStyle(fontSize: 32,
               fontWeight: ui.FontWeight.w500),
               ),
              Padding(padding: EdgeInsets.all(10.0)),
              TextField(
                controller: _controller,
                style: TextStyle(fontSize: 24),
                minLines: 1,
                maxLines: 5,
              )
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            child: Icon(Icons.open_in_new),
            onPressed: () async {
              final value = await loadIt();
              setState(() {
                _controller.text = value;
              });
              showDialog(
                context: context,
                builder: (BuildContext context) =>
                    AlertDialog(
                      title: Text("loaded!"),
                      content: Text("load message from Asset."),
                    )
              );
            }
          )
    );
  }

  Future<String> getDataAsset(String path) async {
    return await rootBundle.loadString(path);
  }

  Future<String> loadIt() async {
    try {
      final res = await getDataAsset(_fname);
      return res;
    } catch (e) {
      return '*** no data ***';
    }
  }
}

【flutter】アニメーション

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState(){
    super.initState();
    controller = AnimationController(
      duration: const Duration(seconds: 3),
      vsync: this
    );
    animation = Tween<double>(begin: 0, end: pi*2)
      .animate(controller)
      ..addListener(() {
        setState((){
        });
      });
    controller.repeat(reverse: false);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255,255,255),
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body: Center(
        child:Column(
          children: [
            Padding(padding: EdgeInsets.all(10)),
            Container(
              width: 300,
              height: 300,
              child: CustomPaint(
                painter: MyPainter(animation.value),
                child: Center(),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  final double value;

  MyPainter(this.value);

  @override
  void paint(Canvas canvas, Size size){
    Paint p = Paint();
    canvas.save();

    p.style = PaintingStyle.fill;
    p.color = Color.fromARGB(100, 255, 0, 255);
    Rect r = Rect.fromLTWH(0,0,250,250);
    canvas.translate(150, 250);
    canvas.rotate(value);
    canvas.translate(-125, -125);
    canvas.drawRect(r, p);

    canvas.restore();
    p.style = PaintingStyle.stroke;
    p.strokeWidth = 25;
    p.color = Color.fromARGB(100, 0, 255, 255);
    r = Rect.fromLTWH(0, 0, 250, 250);
    canvas.translate(150, 250);
    canvas.rotate(value * - 1);
    canvas.translate(-125, -125);
    canvas.drawRect(r, p);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

アニメーションウィジェット

class _MyHomePageState extends State<MyHomePage> {
  bool flg = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child:Column(
          children: [
                AnimatedAlign(
                  alignment: flg ? Alignment.topLeft : Alignment.topRight,
                  duration: const Duration(seconds: 1),
                  child: Container(
                    color: Colors.red,
                    width: 100,
                    height: 100,
                  ),
                  curve: Curves.linear,
                ),
              ],
            ),
            ),
          floatingActionButton: FloatingActionButton(
            onPressed:(){
              setState((){
                flg = !flg;
              });
            },
            child: const Icon(Icons.star),
          ),
    );
  }
}

AnimatedDefaultTextStyleによるテキスト操作

      body: Padding(
        padding: EdgeInsets.all(20),
        child:Column(
          children: [
                AnimatedDefaultTextStyle(
                  duration: const Duration(seconds: 1),
                  style: TextStyle(
                    fontSize: flg ? 48 : 96,
                    fontWeight: FontWeight.bold,
                    color: flg ? Colors.red : Colors.blue
                  ),
                  child: Text("Hello Flutter"),
                ),
              ],
            ),
            ),

ウィジェットを動かす

      body: Padding(
        padding: EdgeInsets.all(20),
        child:Stack(
          children: [
                AnimatedPositioned(
                  duration: const Duration(seconds: 3),
                  top: flg ? 300 : 0,
                  left: flg ? 0 : 300,
                  child: Container(
                    color: Colors.red,
                    width: 100,
                    height: 100,
                  )
                ),
              ],
            ),
            ),

AnimatedCrossFadeによるウィジェットの切り替え

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child:Column(
          children: [
                AnimatedCrossFade(
                  duration: const Duration(seconds: 1),
                  firstChild: const FlutterLogo(
                    style: FlutterLogoStyle.horizontal,
                    size: 300.0),
                  secondChild: const FlutterLogo(
                  style: FlutterLogoStyle.stacked,
                  size: 300.0),
                  crossFadeState: flg ? CrossFadeState.showFirst : CrossFadeState.showSecond,
                ),
              ],
            ),
            ),

【flutter】グラフィック描画のイベント処理

class _MyHomePageState extends State<MyHomePage>{
  static List<Offset> _points = [];

  @override
  void initState(){
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255,255,255),
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body: Center(
        child: Listener(
          onPointerDown: _addPoint,
          child: CustomPaint(
            painter: MyPainter(_points),
            child: Center(),
          ),
        ),
      )
    );
  }
  void _addPoint(PointerDownEvent event) {
    setState((){
      _points.add(event.localPosition);
    });
  }
}

class MyPainter extends CustomPainter {
  final List<Offset> _points;

  MyPainter(this._points);

  @override
  void paint(Canvas canvas, Size size){
    Paint p = Paint();

    p.style = PaintingStyle.fill;
    p.color = Color.fromARGB(100, 0, 200, 100);
    for(var pos in _points) {
      Rect r = Rect.fromLTWH(pos.dx - 25, pos.dy - 25, 50.0, 50.0);
      canvas.drawOval(r, p);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

UIウィジェットで操作

class _MyHomePageState extends State<MyHomePage>{
  static double _value = 0;
  static double _opaq = 0;

  @override
  void initState(){
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255,255,255),
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body: Column(
        children: [
          Padding(padding: EdgeInsets.all(10)),
          Container(
            width: 300,
            height: 300,
            child: CustomPaint(
              painter: MyPainter(_value, _opaq.toInt()),
              child: Center(),
            ),
          ),
          Slider(
            min: 0.0,
            max: 300.0,
            value:_value,
            onChanged: _changeVal,
          ),
          Slider(
            min:0.0,
            max:255.0,
            value:_opaq,
            onChanged: _changeOpaq,
          ),
        ],
      ),
    );
  }
  void _changeVal(double value) {
    setState((){
      _value = value;
    });
  }
  void _changeOpaq(double value) {
    setState((){
      _opaq = value;
    });
  }
}

class MyPainter extends CustomPainter {
  final double _value;
  final int _opaq;

  MyPainter(this._value, this._opaq);

  @override
  void paint(Canvas canvas, Size size){
    Paint p = Paint();

    p.style = PaintingStyle.fill;
    p.color = Color.fromARGB(_opaq, 0, 200, 100);
    Rect r = Rect.fromLTWH(
        (size.width - _value) / 2,
        (size.height - _value) / 2,
      _value, _value);
    canvas.drawOval(r, p);

    r = Rect.fromLTWH(0, 0, size.width, size.height);
    p.style = PaintingStyle.stroke;
    p.color = Color.fromARGB(255, 100, 100, 100);
    canvas.drawRect(r, p);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

ValueNotifierによる更新

class _MyHomePageState extends State<MyHomePage>{
  static ValueNotifier<int> _value = ValueNotifier<int>(0);

  @override
  void initState(){
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255,255,255),
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body: Center(
        child:Column(
          children: [
            Padding(padding: EdgeInsets.all(10)),
            Container(
              width: 300,
              height: 300,
              child: CustomPaint(
                painter: MyPainter(_value),
                child: Center(),
              ),
            ),
            Padding(padding: EdgeInsets.all(5)),
            ElevatedButton(
              child: Text("Click",
              style: TextStyle(fontSize: 32),),
              onPressed: ()=> _value.value++,
            ),
          ],
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  final ValueNotifier<int> _value;

  MyPainter(this._value);

  @override
  void paint(Canvas canvas, Size size){
    Paint p = Paint();

    p.style = PaintingStyle.fill;
    p.color = Color.fromARGB(50, 0, 255, 255);
    Rect r;
    for (var i = 0 ; i < _value.value; i++){
      r = Rect.fromLTWH(10+i*20, 10+i*20, 100, 100);
      canvas.drawRect(r, p);
    }
    r = Rect.fromLTWH(0, 0, size.width, size.height);
    p.style = PaintingStyle.stroke;
    p.color = Color.fromARGB(255, 100, 100, 100);
    canvas.drawRect(r, p);
    if (_value.value > 10) _value.value = 0;
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

【flutter】パスと座標変換

class _MyHomePageState extends State<MyHomePage>{

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255,255,255),
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body:Container(
        child: CustomPaint(
          painter: MyPainter(),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {

  @override
  void paint(Canvas canvas, Size size){
    Path path = Path();
    Rect r = Rect.fromLTWH(50.0, 50.0, 75.0, 75.0);
    path.addOval(r);
    r = Rect.fromLTWH(75.0, 75.0, 125.0, 125.0);
    path.addOval(r);
    r = Rect.fromLTWH(125.0, 125.0, 175.0, 175.0);
    path.addOval(r);
    Paint p = Paint();
    p.color = Color.fromARGB(150, 255, 0, 0);
    p.style = PaintingStyle.fill;
    canvas.drawPath(path, p);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
class MyPainter extends CustomPainter {

  @override
  void paint(Canvas canvas, Size size){
    Path path = Path();
    Rect r = Rect.fromLTWH(50.0, 50.0, 75.0, 75.0);
    path.addOval(r);
    r = Rect.fromLTWH(75.0, 75.0, 125.0, 125.0);
    path.addOval(r);
    r = Rect.fromLTWH(125.0, 125.0, 175.0, 175.0);
    path.addOval(r);

    canvas.save();

    Paint p = Paint();
    p.color = Color.fromARGB(150, 255, 0, 0);
    p.style = PaintingStyle.fill;
    canvas.drawPath(path, p);

    canvas.translate(0.0, 100.0);
    p.color = Color.fromARGB(150, 0, 0, 255);
    canvas.drawPath(path, p);

    p.color = Color.fromARGB(150, 0, 255, 0);
    canvas.rotate(-0.5 * pi);
    canvas.translate(-500.0, 50.0);
    canvas.scale(1 * 1.5);
    canvas.drawPath(path, p);

    canvas.restore();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

【flutter】イメージの描画

イメージはアプリケーション内の「assets」というフォルダに配置するのが一般的
flutter_app/assets/images/image.jpg

pubspec.yamlにassetsを追加する

flutter:
 assets:
  - assets/images/image.jpg
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:typed_data';
import 'dart:ui' as ui;

class _MyHomePageState extends State<MyHomePage>{

  static ui.Image? _img = null;
  static bool _flg = false;

  Future<void> loadAssetImage(String fname) async {
    final bd = await rootBundle.load("images/$fname");
    final Uint8List u8lst = await Uint8List.view(bd.buffer);
    final codec = await ui.instantiateImageCodec(u8lst);
    final frameInfo = await codec.getNextFrame();
    _img = frameInfo.image;
    setState(()=> _flg = true);
  }

  @override
  Widget build(BuildContext context) {
    loadAssetImage('image.jpg');

    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255,255,255),
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body:Container(
        child: CustomPaint(
          painter: MyPainter(_img),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  ui.Image? _img = null;

  MyPainter(this._img);

  @override
  void paint(Canvas canvas, Size size){
    Paint p = Paint();

    Offset off = Offset(50.0, 50.0);
    if(_img != null){
      canvas.drawImage(_img!, off, p);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

【flutter】グラフィック描画の基本

class _MyHomePageState extends State<MyHomePage>{

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255,255,255),
      appBar: AppBar(
        title: Text('App Name', style: TextStyle(fontSize: 30.0),),
      ),
      body:Container(
        child: CustomPaint(
          painter: MyPainter(),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size){
    Paint p = Paint();

    p.style = PaintingStyle.fill;
    p.color = Color.fromARGB(150, 0, 200, 255);
    Rect r = Rect.fromLTWH(50.0, 50.0, 150.0, 150.0);
    canvas.drawRect(r, p);

    p.style = PaintingStyle.stroke;
    p.color = Color.fromARGB(150, 200, 0, 255);
    p.strokeWidth = 10.0;
    r = Rect.fromLTWH(100.0, 100.0, 150.0, 150.0);
    canvas.drawRect(r, p);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

楕円の描画

  void paint(Canvas canvas, Size size){
    Paint p = Paint();

    p.style = PaintingStyle.fill;
    p.color = Color.fromARGB(150, 0, 200, 255);
    Offset ctr = Offset(100.0, 100.0);
    canvas.drawCircle(ctr, 75.0, p);

    p.style = PaintingStyle.stroke;
    p.color = Color.fromARGB(150, 200, 0, 255);
    p.strokeWidth = 10.0;
    Rect r = Rect.fromLTWH(100.0, 50.0, 200.0, 150.0);
    canvas.drawRect(r, p);

    r = Rect.fromLTWH(50.0, 100.0, 150.0, 200.0);
    canvas.drawOval(r, p);
  }

直線の描画

    p.style = PaintingStyle.stroke;
    p.strokeWidth = 5.0;
    p.color = Color.fromARGB(150, 0, 200, 255);
    for (var i = 0; i <= 10; i++) {
      Rect r = Rect.fromLTRB(
        50.0 + 20 * i, 50.0,
        50.0, 250.0 - 20 * i);
      canvas.drawLine(r.topLeft, r.bottomRight, p);
    }

  }

テキストの描画

@override
  void paint(Canvas canvas, Size size){
    Paint p = Paint();

    ui.ParagraphBuilder builder = ui.ParagraphBuilder(
      ui.ParagraphStyle(textDirection: TextDirection.ltr),
    )
    ..pushStyle(ui.TextStyle(color: Colors.red, fontSize: 48.0))
    ..addText('Hello!')
      ..pushStyle(ui.TextStyle(color: Colors.blue[700], fontSize: 30.0))
      ..addText('This is a sample of paragraph text.')
    ..pushStyle(ui.TextStyle(color: Colors.blue[200], fontSize: 30.0))
    ..addText('You can draw Multi-font text!.');

    ui.Paragraph paragraph = builder.build()
    ..layout(ui.ParagraphConstraints(width: 300.0));

    Offset off = Offset(50.0, 50.0);
    canvas.drawParagraph(paragraph, off);

  }

【flutter】タブビューとドロワー

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}
class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Generated App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: const Color(0xFF2196f3),
        canvasColor: const Color(0xFFfafafa),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
  with SingleTickerProviderStateMixin {

  static const List<Tab> tabs = <Tab>[
    Tab(text: 'One'),
    Tab(text: 'Two'),
    Tab(text: 'Three'),
  ];

  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController (
      vsync: this,
      length: tabs.length
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
        bottom: TabBar(
          controller: _tabController,
          tabs: tabs,
        ),
      ),

      body: TabBarView(
        controller: _tabController,
        children: tabs.map((Tab tab) {
          return createTab(tab);
        }).toList(),
      ),
    );
  }

  Widget createTab(Tab tab){
    return Center(
      child: Text(
        'This is "${tab.text}" Tab.',
        style: const TextStyle(
          fontSize: 32.0,
          color: Colors.blue,
        ),
      )
    );
  }
} 

画面下部にタブバーを表示

  static const List<Tab> tabs = <Tab>[
    Tab(text: 'One', icon:Icon(Icons.star)),
    Tab(text: 'Two', icon:Icon(Icons.info)),
    Tab(text: 'Three', icon:Icon(Icons.home)),
  ];

  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController (
      vsync: this,
      length: tabs.length
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
      bottomNavigationBar:Container(
        color: Colors.blue,
        child:TabBar(
          controller: _tabController,
          tabs:tabs,
        ),
      ),

      body: TabBarView(
        controller: _tabController,
        children: tabs.map((Tab tab) {
          return createTab(tab);
        }).toList(),
      ),
    );
  }

drawer

class _MyHomePageState extends State<MyHomePage>{

  static var _items = <Widget>[];
  static var _message = 'ok.';
  static var _tapped = 0;

  @override
  void initState() {
    super.initState();
    for(var i = 0; i < 5; i++) {
      var item = ListTile(
          leading: const Icon(Icons.android),
          title: Text('No, $i'),
          onTap: () {
            _tapped = i;
            tapItem();
          }
      );
      _items.add(item);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter App'),
      ),
      body: Center(
        child: Text(
          _message,
          style: const TextStyle(
            fontSize: 32.0,
          ),
        ),
      ),
      drawer: Drawer(
        child: ListView(
          shrinkWrap: true,
          padding: const EdgeInsets.all(20.0),
          children: _items,
        ),
      ),
    );
  }

  void tapItem(){
      Navigator.pop(context);
      setState((){
        _message = 'tapped:[$_tapped]';
      });
  }
}