はじめに
今回、Flutterでとあるアプリを開発していきたいのでそれらの備忘録をこちらにまとめていきます。
警告
あくまで備忘録のサンプルコードなので実行は自己責任でお願いします。
サンプルコードはWebベースでも走らせることができその際に前回でも利用した
Dartpadが便利なのでぜひご利用しながら試してみてください
Flutterをする上でDartに関する知識が必要になってきますのでその基礎などをまとめているのでぜひこちらもご覧下さい
また非常に有意義な資料がこちらにもあるので参考にしてみてください
アプリ開発における基礎知識
ウィジェット(widget)
アプリケーションを開発していくにあたってよく「ウィジェット」という言葉を耳にします。
アプリの特に重要なデータや機能を「ひと目で」確認できるようにし、そうしたデータや機能にユーザーのホーム画面から直接アクセスできるようにするもの
上記のような解説でAndroid Studio公式さんは言ってます(詳しくはリンク参照で)
画面に表示されているUIの部品だと考えてもらってもいいっぽい
Stateless(ステートレス)とStateful(ステートフル)
Stateless → 初期化などしたら基本的に 変更がないもの
- 使いどころ:静的なUIなどの部分(基本一度定義されたら変更のないもの)
- 例: ボタンの色や固定された背景色など
Stateful → 変更などを 動的に 管理できるもの
- 使いどころ:ユーザーなどの動作によって 変化があるところ
- 例 : カウンターやユーザーの情報など
大きな違いとして「状態の変化」があるか無いか
本編
開発環境
今回使用している開発環境
OS:Windows11 Pro
IDE:VScode
Flutterバージョン:3.24.5
エミュレーター:Pixel 9 Pro XL API
ウィジェット各種について
表示についての基礎
今回はサンプル画面このようなサンプル画面を表示されるようなものを作るとします。
(文章はGPT大先生より)
簡単にこれでやっていることの説明
- サンプルプログラムを削除して、アプリのど真ん中に長い文章を6行で表示させるようにしている。
ここで使用しているウィジェット
- CenterWidget
- ChildWidget
- TextWidget
- TextStyleWidget
ウィジェットはある程度メソッドと考えてもOK
イメージとしては 引数として 要素を受け渡していっている
それらが 一つになり一つの画面 を生み出している。
ウィジット説明
CenterWidget
→ 中央に配置するものを定義
ChildWidget
→ センターの子ウィジェットにとなりそこに要素を入れる
TextWidget
→ テキストを配置するためのウィジェット
TextStyleWidget
→ テキストの大きさなどを指定
引数として maxLines(何行で表示するか)
を6行にして
overflow
もし文字列が横幅を越したとき ellipis(訳:省略)
として「...」を表示する。
また、フォントの色を黒色,大きさを16と定義している。
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
// Class MyHomePageState
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: const Center(
child: Text(
'Flutterは、Googleが提供するモバイルアプリケーションフレームワークであり、単一のコードベースからAndroidおよびiOS用の高品質なアプリを構築できます。このテキストは長い文章の例として追加していますが、maxLinesプロパティによって行数が制限され、overflowプロパティで適切に処理されます。',
maxLines: 6, // 6行に設定
overflow: TextOverflow.ellipsis, // 3点リーダーで省略
style: TextStyle(
fontSize: 16, // フォントサイズ
color: Colors.black, // テキストの色
),// textStyle
), // child
), // center
); // Scaffold
} // build
} // class
上記の例のように色々ととウィジットによって管理でき,カスタマイズできるので皆さんも調べて試してみてください~
他詳細は以下の資料を見てください
Containerで遊んでみる(興味ある方のみどうぞ笑)
Containerウィジェットを利用することによって色々と表示で遊べます(下記のリンク参照)
https://api.flutter.dev/flutter/widgets/Container-class.html
ここに乗っているサンプルをもとにサンプルを上げて遊んでみたいと思います。(遊び心大事)
例長方形の中にテキストを入れ込む(コンテナーで体裁管理)
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
// アプリのボディ部分
body: Center( // 真ん中に
child: Container( // コンテナーとして
padding: const EdgeInsets.all(20), // 余白を追加
decoration: BoxDecoration(
shape: BoxShape.rectangle, // 長方形を指定
borderRadius: BorderRadius.circular(12), // 角を丸くする
color: Colors.blue, // 背景色
),
child: const Text( // コンテナーの子ウィジェットとしてテキスト定義
"コンテナーで遊ぼう",
style: TextStyle(
color: Colors.white, // テキストの色
fontSize: 18, // フォントサイズ
),
),
),
),
);
}
}
こんな感じで表示を遊ぶこともできます。
楽しくなってきたでしょう。
画像表示系
image.networkウィジェット
画像のリンクからアプリに表示させることができるもである。
今回はとても美味しかった、骨付き肉を堂々と画面中央に表示したいと思います。
以下元画像(これ実は羊肉です笑)
ご自由にお使いください
それでは気を取り直して
Image.network
について
このウィジェットでは引数として以下のものを設定できます(一部抜粋)
-
src
→ 画像のアドレスを指定(リンク) -
width / height
→double型
で認識されて縦幅、横幅を指定できる -
fit
→ アスペクト比(縦横比)を変えてもはみ出さないようにする(親ウィジェット内で表示する)ための引数
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Image.network(
'https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628177/ff9dc245-ae03-5537-0b2d-9c83fc2b8053.png',
width: 300, // 画像の幅を指定
height: 250, // 画像の高さを指定
fit: BoxFit.cover, // 親要素に合わせて表示
),
),
);
}
}
(ChatGPTに聞いたら画像ロードを判定させてロードのUIを表示させるとかできるらしい)
Image.assetウィジェット
今回のウィジェットはローカルファイルから画像を表示するウィジェットです。
今回は画像を変えてこれをローカルファイルから参照して画面中央に堂々と表示するようにしてみる
やり方
①プロジェクトフォルダの中にassets(任意で可能)フォルダを作成して画像を入れる
② pubspec.yaml にパスを通す
プロジェクトフォルダの一番上の階層に入っています。
pubspec.yamlに設定を記述していきます。
# To add assets to your application, add an assets section, like this:
assets: # 最初ここはコメントになっている
# 相対パスを記述
- assets/S__53043236.jpg # ここは自分で記述
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
コメントでも書いてますが「assets」はコメントになっておりコメントを外してあげて相対パスを記述してあげることにより使用できるようになります。
③実際にウィジェットを利用してみる
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Image.asset(
'assets/S__53043236.jpg',
width: 300, // 画像の幅を指定
height: 250, // 画像の高さを指定
fit: BoxFit.cover, // 親要素に合わせて表示
),
),
);
}
}
これで画像表示系は終わりです。
Paddingウィジェット
子ウィジェットにPadding(余白)を追加するウィジェットです。
子としてTextを持ちます
画面遷移イメージ
以下は、2つの画面を横並びに表示し、遷移の流れを示したものです。
変更前 | 変更後 |
---|---|
このようにして子ウィジェットにあたる「 Text 」に余白を持たせることのウェイジェットになっています。
実際のコード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Container(
color: Colors.green,
child: Padding(
padding: const EdgeInsets.all(24.0), // パディングを追加
child: const Text(
"なんか色々と長めの文章を書いてみます。文章力がないのでなかなか文章が思いつかないですが頑張って文字書いてます。最近、美味しいシュークリーム屋さんを発見してテンションが結構上がってます。やったねー!",
style: TextStyle(
color: Colors.white, // 文字色を白に設定
fontSize: 16, // フォントサイズを設定
),
),
),
),
);
}
}
paddingウィジェットの引数設定について(ChatGPTより)
引数呼び出しの際は名前付き引数となっており,明示的に引き渡す引数名を書く必要がある。
また、引数を一つだけでも指定は可能。
メソッド | 説明 | 使用例 |
---|---|---|
EdgeInsets.all |
全方向(上下左右)に同じ余白を設定する | EdgeInsets.all(8.0) |
EdgeInsets.only |
特定の方向(left , top , right , bottom )に余白を設定する |
EdgeInsets.only(left: 8.0) |
EdgeInsets.symmetric |
水平方向(horizontal )または垂直方向(vertical )に均等な余白を設定する |
EdgeInsets.symmetric(horizontal: 16.0) |
EdgeInsets.fromLTRB |
左(left )、上(top )、右(right )、下(bottom )の4方向それぞれに余白を設定する。 |
EdgeInsets.fromLTRB(8.0, 16.0, 8.0, 16.0) |
ColoredBoxウィジェット
指定したウィジェットの範囲をカラーボックスで囲むことのできるウィジェット
ちなにみPaddingウィジェットの子要素としても埋め込める
こんな感じで色々と遊べます。
コード例(Paddingを含んだバージョン)
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: ColoredBox(
color: Colors.red,
child: Padding(
padding: EdgeInsets.all(20),
child: const Text(
"テスト的な文章",
style: TextStyle(
color: Colors.white,
fontSize: 20,
) // Padding
),//TextStyle
), // Text
), // ColoredBox
);
}
}
色などの設定で使えるメソッド(Colorクラスのメソッド)
メソッド名 | 説明 |
---|---|
fromARGB(int a, int r, int g, int b) |
ARGB(アルファ、赤、緑、青)で色を生成します。a は透明度、r は赤、g は緑、b は青の設定ができる |
withOpacity(double opacity) |
色の不透明度を変更した新しい色を返します。opacity は 0.0 から 1.0 の範囲で指定できる。 |
computeLuminance() |
色の明るさ(輝度)を計算し、0.0(暗い)から 1.0(明るい)の範囲で返す |
toString() |
色を文字列として返す |
となっており、今回のColorBoxのcolor引数として上記のメソッドを渡してやると自由に変えることができる。
Alignウィジェット
上下左右の配置を設定できるウィジェット
場所の指定するテンプレ
Align(
alignment: Alignment.// 指定する設定
child: Text("テキスト")
こんな書き方をする
設定できるものとして以下のようなものがある
メソッド/プロパティ | 説明 |
---|---|
Alignment.topLeft |
ウィジェットを左上に配置する。 |
Alignment.topCenter |
ウィジェットを上中央に配置する。 |
Alignment.topRight |
ウィジェットを右上に配置する。 |
Alignment.centerLeft |
ウィジェットを中央左に配置する。 |
Alignment.center |
ウィジェットを完全に中央に配置する。 |
Alignment.centerRight |
ウィジェットを中央右に配置する。 |
Alignment.bottomLeft |
ウィジェットを左下に配置する。 |
Alignment.bottomCenter |
ウィジェットを下中央に配置する。 |
Alignment.bottomRight |
ウィジェットを右下に配置する。 |
Alignment(x, y) |
ウィジェットを指定した位置に配置する。x とy は-1.0から1.0の範囲で、-1.0は左や上、1.0は右や下を意味する。 |
使用例(画像)
今回はtopCenterメソッド利用してみた
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Align(
alignment: Alignment.topCenter,
child: Text(
"テスト的な文章"
),
),
);
}
}
ボタン系ウィジェット
Textbuttonウィジェット
画面にボタンを追加するウィジェット
基本文法
TextButton(
// ボタンが押されたとき
onPressed:(){
// ここに処理を記述
},
// ボタン押されていないとき
child: // 任意のウィジェット
)
今回、出力する画面例はこちらです
ボタンが押されたらコンソールに「もう来ないからね~」
と表示されます。
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: TextButton(
onPressed: () {
// ボタンが押されたときの処理を記述
print("もう来ないからね~");
},
child: const Text("ボタン押してね~"),
),
),
);
}
}
Elevatedbuttonウィジェット
同じボタン系のウィジェットであるが立体的に結構わかりやすく視覚的にボタンを追加できる
画面出力例
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
const Color.fromARGB(255, 17, 244, 17), // ボタンの背景色を濃く設定
),
onPressed: () {
// ボタンが押されたときの処理
print("もう来ないからね~");
},
child: const Text("ボタン押してね~"),
),
),
);
}
}
ボタンの丸みを調整できるためのウィジェットもあり
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
// ボタンの背景色指定
const Color.fromARGB(255, 17, 244, 17), // ボタンの背景色を濃く設定
// 角をどれだけ丸にするかの設定
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)
) // RoundedRectangleBorder
), // style
// ...続く
のようにするとボタンの丸みを調整できる
完全な丸にするとき
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 17, 244, 17), // 背景色
shape: const CircleBorder(), // 角を丸く設定
padding: const EdgeInsets.all(70), // パディング
),
OutlineButtoneウィジェットについて
これもボタンの一種です
これもほぼ同じなので詳細は割愛します
Centerの子ウィジェットにOutlineButtonと書くだけで他同じです
AlrtDialogウィジェット
ダイアログを表示するウィジェットで大体なにかの処理の後なので
「 showDialog関数 」で呼び出すようにする
このウィジェットは3つの構成要素を持ち
title → ダイアログ表示時のタイトル
content → ダイアログ内で行処理などのウィジェット
action → ダイアログが表示されたあとどのような動作でなにをするか
基本文法
showDialog(context: context,builder: (context){
return AlertDialog(
title: // ダイアログのタイトル
content: // ダイアログ内の内容
action: //ダイアログ内の処理
);
画面例(TextButtonウィジェットと組み合わせてます)
ボタン押下前 | ボタン押下後 |
---|---|
コード例
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: TextButton(
onPressed: () {
// ボタンが押されたときの処理を記述
print("もう来ないからね~");
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("○っち"),
content: Text("もう来ないからね~"),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("close"))
],
);
});
},
child: const Text("ボタン押してね~"),
),
),
);
}
}
最後に
あまり綺麗ではない備忘録を最後までご閲覧いただきありがとうございました。
備忘録なのでどんどん更新していくと思いますのでご期待ください。
ご指摘や「これいいよ!」とかあればぜひコメントいただけると嬉しいです。
僕みたいな初学者の方の足しに少しでもなればいいと思います。
参考にさせていただいた記事,資料など