【Flutter】スプライトの利用

class MySprite extends SpriteComponent {
  late final Vector2 _position;

  MySprite(this._position): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    sprite = await Sprite.load('chara.png');
    position = _position;
    size = Vector2(100, 100);
  }

  @override
  void update(double delta) {
    super.update(delta);
  }
}
class SampleGame extends FlameGame with HasTappableComponents {
  Vector2 _position = Vector2(100, 100);
  final List<PositionComponent> _sprites = <PositionComponent>[];

  @override
  Color backgroundColor() => const Color(0xffCCCCFF);

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    var sp1 = GreenRectSprite(Vector2(200, 100));
    _sprites.add(sp1);
    add(sp1);
    var sp2 = RedCircleSprite(Vector2(100, 200));
    _sprites.add(sp2);
    add(sp2);
    add(WhiteTextSprite(Vector2(25, 25)));
  }

  @override
  void onTapDown(TapDownEvent event) {
    _position = event.canvasPosition - Vector2(50, 50);
    super.onTapDown(event);
  }
}

class RedCircleSprite extends CircleComponent
  with HasGameRef<SampleGame> {
  late Vector2 _position;

  RedCircleSprite(this._position): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    setColor(Colors.red);
    position = _position;
    size = Vector2(100, 100);
  }

  @override
  void update(double delta) {
    final d = (gameRef._position - position) / 10;
    position += d * delta * 100;
    super.update(delta);
  }
}

class GreenRectSprite extends PositionComponent with HasGameRef<SampleGame>{
  late Vector2 _position;
  late Paint _paint;

  GreenRectSprite(this._position): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    position = _position;
    size = Vector2(100, 100);
    _paint = Paint()
      ..style = PaintingStyle.fill
      ..color = Colors.green;
  }

  @override
  void update(double delta) {
    final d = (gameRef._position - position) / 50;
    position += d * delta * 100;
    super.update(delta);
  }
}

class GreenRectSprite extends PositionComponent
  with HasGameRef<SampleGame> {
  late Vector2 _position;
  late Paint _paint;

  GreenRectSprite(this._position): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    position = _position;
    size = Vector2(100, 100);
    _paint = Paint()
      ..style = PaintingStyle.fill
      ..color = Colors.green;
  }

  @override
  void update(double delta) {
    final d = (gameRef._position - position) / 50;
    position += d * delta * 100;
    super.update(delta);
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    final r = Rect.fromLTWH(0, 0, 100, 100);
    canvas.drawRect(r, _paint);
  }
}

class WhiteTextSprite extends TextComponent {
  late Vector2 _position;

  WhiteTextSprite(this._position): super();

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    position = _position;
    text = "Hello Flame";
    textRenderer = TextPaint(
      style: TextStyle(
        fontSize: 48.0,
        fontWeight: FontWeight.bold,
        color: Colors.white,
      ),
    );
  }
}

【Flutter】flame

$ flutter pub add flame
$ flutter pub upgrade flame

import 'package:flutter/material.dart';
import 'package:flame/game.dart';

void main() async {
  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> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
        body: GameWidget(game: SampleGame())
    );
  }
}

class SampleGame extends FlameGame {
  late final paint;

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    paint = Paint();
    paint.color = Colors.blue;
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    final rect = Rect.fromLTWH(100, 100, 100, 100);
    canvas.drawOval(rect, paint);
  }
}

キーで図形を操作する

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
        body: GameWidget(game: SampleGame())
    );
  }
}

class SampleGame extends FlameGame with KeyboardEvents {
  late final paint;
  late Vector2 _loc;

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    paint = Paint();
    paint.color = Colors.blue;
    _loc = Vector2(100, 100);
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    final rect = Rect.fromLTWH(_loc.x, _loc.y, 100, 100);
    canvas.drawOval(rect, paint);
  }

  @override
    KeyEventResult onKeyEvent(
      RawKeyEvent event,
      Set<LogicalKeyboardKey> keysPressed,
      ) {
    final _dpos = Vector2(0, 0);

    if (event.character == 'j') {
      _dpos.x = -10;
    }
    if (event.character == 'l') {
      _dpos.x = 10;
    }
    if (event.character == 'i') {
      _dpos.y = -10.0;
    }
    if (event.character == 'k') {
      _dpos.y = 10;
    }
    _loc += _dpos;
    return KeyEventResult.handled;

  }
}

【Flutter】Firebase Authenticationによるユーザ認証

firestoreのセキュリティルール

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {

    match /{document=**} {
      allow read, write: if request.time < timestamp.date(2023, 10, 3);
    }
  }
}

認証されたユーザのみ許可に変更

    match /{document=**} {
      allow read, write: if request.auth != null && request.auth.uid != null;
    }

### Authenticationによるユーザ認証
FirebaseのauthenticationでGoogleを許可する
$ flutter pub add firebase_auth
$ flutter pub upgrade firebase_auth
$ flutter pub add google_sign_in
$ flutter pub upgrade google_sign_in

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';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  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();
  static const url = 'https://jsonplaceholder.typicode.com/posts';

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

  @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: () {
              doSignin();
            }
          )
    );
  }

  void addDoc() async {
    var msg = _controller.text;
    final input = msg.split(',');
    final data = {
      'name': input[0],
      'mail': input[1],
      'age': input[2]
    };
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    final snapshot = await firestore.collection('mydata')
      .add(data);
    fire();
  }

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

  Future<UserCredential> signInWithGoogle() async {
    final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
    final GoogleSignInAuthentication? googleAuth = await googleUser?.authentication;
    final credential = GoogleAuthProvider.credential(
      accessToken: googleAuth?.accessToken,
      idToken: googleAuth?.idToken,
    );
    return await FirebaseAuth.instance.signInWithCredential(credential);
  }

  void doSignin() {
    signInWithGoogle().then((value) {
      if(value.user != null) {
        fire();
      }
    });
  }
}

【Flutter】Firebase検索とソート

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

final snapshot = await firestore.collection(‘mydata’)
.orderBy(‘name’, descending: false)
.startAt([msg])
.endAt([msg + ‘\utf8ff’])
.get();

descendingはflaseだと昇順、trueだと降順にデータが並べられる

### データの追加

  void addDoc() async {
    var msg = _controller.text;
    final input = msg.split(',');
    final data = {
      'name': input[0],
      'mail': input[1],
      'age': input[2]
    };
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    final snapshot = await firestore.collection('mydata')
      .add(data);
    fire();
  }

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

【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;
}