📎

【Dart/Flutter】簡単なUI向けコピペ集

2023/02/13に公開

変換用辞書、ショートカットキー等に割り当て、簡単なUIをスムーズにコード作成する目的となります。

(覚えていれば不要と思いますが、何かのヒントとして。)

コード内容別案や、IDEの自動作成等、方法は種々あると思います。

最後にコピペを利用したべた書きとして、とてもシンプルなTodoアプリコードを記載しております。まだまだですが、思いついたものを理解したものの組み合わせで、一瞬で作れるようにしていきたいですね。

【Dart/Flutter】簡単なUI向けコピペ集

main

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: Scaffold(
        body: Text('MyApp'),
      ),
    );
  }
}

MultiProvider

return MultiProvider(
  providers: [
    ChangeNotifierProvider(
      create: (context) => XxxRepository(),
    ),
  ],
  child: MaterialApp(
    home: Scaffold(
      body: Text('MyApp'),
    ),
  ),
);

Text

const Text(''),

Container

Container(
  padding: const EdgeInsets.all(16),
  color: Colors.cyan,
  child: Text('Container'),
),

Padding

Padding(
  padding: const EdgeInsets.all(16.0),
  child: Container(
    color: Colors.red,
  ),
),

Column

Column(
  mainAxisSize: MainAxisSize.min,
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [],
),

Image

const Image(image: AssetImage('assets/image_000.jpg')),

Image.network

Image.network('https://github.com/iwakuS/tmp_public/blob/master/neko.jpg?raw=true'),

ListView.separated

ListView.separated(
  physics: const NeverScrollableScrollPhysics(),
  // ネストされたリストビュー場合
  primary: false,
  // リスト内のアイテムのスクロールビューに固定の高さを
  // 与えることができるように、true
  shrinkWrap: true,
  scrollDirection: Axis.vertical,
  itemCount: <String>['1', '2', '3'].length,
  itemBuilder: (context, index) {
    final item = <String>['1', '2', '3'][index];
    return Text(item);
  },
  separatorBuilder: (context, index) {
    return const SizedBox(height: 16);
  },
),

GridView.builder

GridView.builder(
  itemCount: <String>['1', '2', '3'].length,
  // ①何列にするかを指定する
  gridDelegate:
      const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),

  // ②タイルの幅を指定(デバイスのwidthよりも大きい500.0指定すると1列表示)
  // gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
  //     maxCrossAxisExtent: 500.0),
  itemBuilder: (context, index) {
    final item = <String>['1', '2', '3'][index];
    return Text(item);
  },
),

Consumer

provider | Flutter Packageのimportが必要

// To Doリストの土台例
Consumer<XxxRepository>(
  builder: (context, repository, child) {
    final items = repository.findAllItems();
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (BuildContext context, int index) {
        return Text(items[index].name);
      },
    );
  },
),

StreamBuilder

StreamBuilder(
  stream: Xxx,
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.active) {
      final items = snapshot.data as List<Yyy>?;
      if (items == null) {
        return Container();
      }
      return const Text('ListView等表示');
    } else {
      return Container();
    }
  },
),

CheckboxListTile

CheckboxListTile(
  value: items[index].isDone,
  title: Text(items[index].name),
  onChanged: (newValue) {
    if (newValue != null) {
      repository.toggleDone(index: index, isDone: newValue);
    }
  },
),

Dismissible

Dismissible(
  key: Key(''),
  direction: DismissDirection.endToStart,
  background: Container(
    color: Colors.red,
    alignment: Alignment.centerRight,
    child: const Icon(
      Icons.delete_forever,
      color: Colors.white,
      size: 50.0,
    ),
  ),
  onDismissed: (direction) {},
  child: Container(
    color: Colors.green,
    width: double.infinity,
  ),
),

showDialog

※上記MyAppより、下位層で利用しないとエラーとなる
(Scaffoldを別ウィジェット利用=class NewWidget extends StatelessWidget)

ElevatedButton(
  onPressed: () {
    showDialog(
      context: context,
      builder: (context) {
        return const Text('AlertDialog等表示');
      },
    );
  },
  child: const Text('Show Dialog'),
),

AlertDialog

AlertDialog(
  title: const Text('Show Dialog'),
  content: const Text('Show Dialog Content'),
  actions: [
    ElevatedButton(
      onPressed: () {
        Navigator.of(context).pop();
      },
      child: const Text('OK'),
    ),
    ElevatedButton(
        onPressed: () => Navigator.of(context).pop(),
        child: const Text('Cancel')),
  ],
),

【備考】Todoアプリ

※上記コピペを利用したべた書き

import 'dart:collection';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (context) => TodoRepository(),
        ),
      ],
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Todo List'),
            actions: [
              // Add
              Consumer<TodoRepository>(
                builder: (context, repository, child) {
                  return GestureDetector(
                    onTap: () {
                      showDialog(
                        context: context,
                        builder: (context) {
                          return AlertDialog(
                            title: const Text('Add'),
                            content: TextField(
                              controller: repository.nameController,
                              onChanged: (value) {
                                repository.nameController.text = value;
                              },
                            ),
                            actions: [
                              ElevatedButton(
                                child: const Text('OK'),
                                onPressed: () {
                                  repository.addTask();
                                  Navigator.of(context).pop();
                                },
                              ),
                              ElevatedButton(
                                child: const Text('Cancel'),
                                onPressed: () {
                                  Navigator.of(context).pop();
                                },
                              ),
                            ],
                          );
                        },
                      );
                    },
                    child: const Padding(
                      padding: EdgeInsets.all(8.0),
                      child: Icon(Icons.add),
                    ),
                  );
                },
              ),
            ],
          ),
          body: Consumer<TodoRepository>(
            builder: (context, repository, child) {
              final items = repository.findAllItems();
              return ListView.builder(
                itemCount: items.length,
                itemBuilder: (BuildContext context, int index) {
                  // return Text(items[index].name);
                  return CheckboxListTile(
                    value: items[index].isDone,
                    title: Text(items[index].name),
                    onChanged: (newValue) {
                      if (newValue != null) {
                        repository.toggleDone(index, newValue);
                      }
                    },
                  );
                },
              );
            },
          ),
        ),
      ),
    );
  }
}

class Task {
  String name;
  bool isDone;

  Task({
    required this.name,
    this.isDone = false,
  });
}

class TodoRepository extends ChangeNotifier {
  final List<Task> _tasks = [Task(name: 'Task1'), Task(name: 'Task2')];
  TextEditingController nameController = TextEditingController();

  UnmodifiableListView<Task> get tasks {
    return UnmodifiableListView(_tasks);
  }

  List<Task> findAllItems() {
    return _tasks;
  }

  void toggleDone(int index, bool isDone) {
    var task = _tasks[index];
    task.isDone = isDone;
    _tasks[index] = task;
    notifyListeners();
  }

  void addTask() {
    final newTask = Task(
      name: nameController.text,
    );
    _tasks.add(newTask);
    notifyListeners();
  }
}

Discussion