目次
概要
オブジェクトとは、いわば設計書。
トランプゲームを思い浮かべてみて欲しい。トランプだったら最低でも大体以下の情報が必要なはず
- カードの絵柄
- カードの数字
- カードの画像
ジョーカーを除くとして、残りの52枚のカードの「絵柄」「数字」「画像」を一つ一つ変数を作るのはとても手間になる。
それを共通のデータの型として定義してあげれば、とてもスムーズになるはずだ!
今回、トランプのボタン全てを表示する処理を行なっているが、メインとなるのはオブジェクトの生成だけ。
View表示に関しては別途説明が必要なものが多い。
ソースコード
pubspec.yaml
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
flutter_riverpod: ^1.0.0-dev.7 //ここ追加
collection: ^1.17.1 //ここ追加
列挙体(トランプのマーク)
enum TrumpMark {
spade,
heart,
dia,
club
}
extension TrumpMarkAdditional on TrumpMark {
String get trumpMarkString {
switch (this) {
case TrumpMark.spade:
return '♠️';
case TrumpMark.heart:
return '';
case TrumpMark.dia:
return '♦️';
case TrumpMark.club:
return '♣️';
}
}
}
オブジェクト生成部分
import 'TrumpMark.dart';
class TrumpCard {
bool isSelected;
int number;
TrumpMark mark;
TrumpCard(this.isSelected, this.number, this.mark);
}
アプリ起動部分
import 'package:concentration/TrumpButton/TrumpButtonView.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: 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.deepOrange),
useMaterial3: true,
),
home: const TrumpButtonView(title: 'Flutter Demo Home Page'),
);
}
}
View部分
import 'package:collection/collection.dart';
import 'package:concentration/Common/TrumpCard.dart';
import 'package:concentration/Common/TrumpMark.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'TrumpButtonViewModel.dart';
class TrumpButtonView extends ConsumerWidget {
const TrumpButtonView({Key? key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context, WidgetRef ref) {
final _viewModel = ref.watch(trumpButtonViewModelProvider);
List<OutlinedButton> trumpButtons = [];
for (TrumpCard trumpCard in _viewModel.trumpCards) {
var trumpButton = OutlinedButton(
onPressed: () { _viewModel.tapped(); },
style: OutlinedButton.styleFrom(
minimumSize: Size(MediaQuery.of(context).size.width/4, 40),
backgroundColor: Colors.white10,
foregroundColor: Colors.black,
),
child: Text("${trumpCard.mark.trumpMarkString} ${trumpCard.number + 1}")
);
trumpButtons.add(trumpButton);
}
final itemsPerRow = 13;
final slicedTrumpButtons = trumpButtons.slices(itemsPerRow).toList();
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text("TrumpButton"),
),
body:
LayoutBuilder(
builder: (context, constraints) => SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: constraints.maxWidth, minHeight: constraints.maxHeight),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (var slicedTrumpButton in slicedTrumpButtons)
columnTrumpButtons(slicedTrumpButton),
]
),
),
)
)
);
}
Widget columnTrumpButtons(List<OutlinedButton> trumpButtons) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (var trumpButton in trumpButtons)
trumpButton,
]
);
}
}
ViewModel部分
import 'dart:ffi';
import 'package:concentration/Common/TrumpMark.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../Common/TrumpCard.dart';
import 'TrumpButtonRepository.dart';
final trumpButtonViewModelProvider = ChangeNotifierProvider((ref) => TrumpButtonViewModel(repository: ref.read(trumpButtonRepositoryRepositoryProvider)));
class TrumpButtonViewModel extends ChangeNotifier {
TrumpButtonRepository? repository;
List<TrumpCard> trumpCards = [];
TrumpButtonViewModel({this.repository}){
List<TrumpCard> trumpCards = [];
for(TrumpMark mark in TrumpMark.values) {
for (int num = 0; num < 13; num ++) {
trumpCards.add(TrumpCard(false, num, mark));
}
}
this.trumpCards = trumpCards;
}
void tapped() {
this.repository?.tapped();
}
}
Repository部分
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'TrumpButtonModel.dart';
final trumpButtonRepositoryRepositoryProvider = Provider((ref) => TrumpButtonRepositoryImpl(model: ref.read(trumpButtonModelModelProvider)));
abstract class TrumpButtonRepository {
void tapped();
}
class TrumpButtonRepositoryImpl implements TrumpButtonRepository {
TrumpButtonRepositoryImpl({required TrumpButtonModel model}): _model = model;
final TrumpButtonModel _model;
void tapped() {
print("タップされたよ!");
}
}
Model部分
import 'package:flutter_riverpod/flutter_riverpod.dart';
final trumpButtonModelModelProvider = Provider((ref) => TrumpButtonModel());
class TrumpButtonModel {
}
スクリーンショット
詳細
オブジェクト生成
オブジェクト生成は以下。
このように定義してあげることで、トランプのカードのデータをまとめて定義できるし、一つのオブジェクトに対して複数のデータを持たせることができる。
class TrumpCard {
bool isSelected;
int number;
TrumpMark mark;
TrumpCard(this.isSelected, this.number, this.mark);
}
以下の部分はコンストラクタと呼ばれ、オブジェクトを実体化した時に最初に呼ばれるもの。
ここでは、初期値を設定している。
TrumpCard(this.isSelected, this.number, this.mark);
インスタンス化の例は以下。
この例では、isSelectedに「false」、numberに「10」、markに「TrumpMark.spade」を格納している。
TrumpCard(false, 10, TrumpMark.spade)
説明が必要な箇所
- 配列(List型)
- 配列の分割
- 列挙体とその拡張
- 繰り返し文
- 多重配列のデータを繰り返し文を使ってまとめて表示
- コード要修正
- 画面の大きさを取得する
参考ページ
- Zenn「【Dart基礎】配列とは」
- Qiita「Dartの制御文(繰り返し)」
- Zenn「Dart のコンストラクタの基本 (できることまとめ)」
- Qiita「Dart enum extensionは便利だぞ」
- Qiita「【Flutter】SingleChildScrollViewの中で上下中央揃えする方法」
- Zenn「Flutter/DartでListの要素を分割する方法4選」
- pub.dev「collection 1.18.0」
- ちょげぶろぐ「[Flutter]Columnの要素を動的に作成するには?」
- tns-blog「Flutter OutlineButtonのサイズの変更方法」
- 2023あずきぱんウェブスタジオ「【Flutter】デバイスの画面サイズを取得する方法」