Contents
Multiply the card into a collection
現在、私たちのカードは、GridViewの子フィールドのインラインで作成されています。
この書き方では、読みにくいネストされたコードになりがちです。 空のカードをいくつでも生成できる関数に抽出(extract)して、カードのリストを返すようにします。
具体的には、build()関数の上に新しいプライベート関数を作成します(アンダースコアで始まる関数はプライベートAPIであることを忘れないでください)。
List<Card> _buildGridCards(int count) {
List<Card> cards = List.generate(
count,
(int index) => Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 18.0 / 11.0,
child: Image.asset('assets/diamond.png'),
),
Padding(
padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Title'),
SizedBox(height: 8.0),
Text('Secondary Text'),
],
),
),
],
),
),
);
return cards;
}
生成されたカードをGridViewの子フィールドに割り当てます。 GridViewに含まれるすべてのものを次の新しいコードに置き換えることを忘れないでください。
//home.dart import 'package:flutter/material.dart'; class HomePage extends StatelessWidget { //↓新しく_buildGridCards()関数を定義 List<Card> _buildGridCards(int count) { List<Card> cards = List.generate( count, (int index) => Card( clipBehavior: Clip.antiAlias, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ AspectRatio( aspectRatio: 18.0 / 11.0, child: Image.asset('assets/diamond.png'), ), Padding( padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text('Title'), SizedBox(height: 8.0), Text('Secondary Text'), ], ), ), ], ), ), ); return cards; } // TODO: Add a variable for Category (104) @override Widget build(BuildContext context) { // TODO: Return an AsymmetricView (104) // TODO: Pass Category variable to AsymmetricView (104) return Scaffold( appBar:AppBar( leading: IconButton( icon: Icon( Icons.menu, semanticLabel: 'menu', ), onPressed: () { print('Menu button'); }, ), title: Text('SHRINE'), actions: <Widget>[ IconButton( icon: Icon( Icons.search, semanticLabel: 'search', ), onPressed: () { print('Search button'); }, ), IconButton( icon: Icon( Icons.tune, semanticLabel: 'filter', ), onPressed: () { print('Filter button'); }, ), ], ), body: GridView.count( crossAxisCount: 2, padding: EdgeInsets.all(16.0), childAspectRatio: 8.0 / 9.0, // TODO: Build a grid of cards (102) children: _buildGridCards(10), //←この部分を置き換え。 ), resizeToAvoidBottomInset: false, ); } }
カードはありますが、まだ意味のあるものは何も表示されていません。 今こそ、いくつかの製品データを追加するときです。
Add product data
アプリには、画像、名前、価格が記載された製品をいくつか表示させたいです。 すでにカードの中にあるウィジェットにそれらを追加しましょう。
次に、home.dartで、データモデル用に提供した新しいパッケージといくつかのファイルをインポートします。
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'model/products_repository.dart';
import 'model/product.dart';
最後に、_buildGridCards()を変更して製品情報を取得し、そのデータをカードで使用します。
List<Card> _buildGridCards(BuildContext context) {
List<Product> products = ProductsRepository.loadProducts(Category.all);
if (products == null || products.isEmpty) {
return const <Card>[];
}
final ThemeData theme = Theme.of(context);
final NumberFormat formatter = NumberFormat.simpleCurrency(
locale: Localizations.localeOf(context).toString());
return products.map((product) {
return Card(
clipBehavior: Clip.antiAlias,
// TODO: Adjust card heights (103)
child: Column(
// TODO: Center items on the card (103)
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 18 / 11,
child: Image.asset(
product.assetName,
package: product.assetPackage,
// TODO: Adjust the box size (102)
),
),
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
child: Column(
// TODO: Align labels to the bottom and center (103)
crossAxisAlignment: CrossAxisAlignment.start,
// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)
Text(
product.name,
style: theme.textTheme.headline6,
maxLines: 1,
),
SizedBox(height: 8.0),
Text(
formatter.format(product.price),
style: theme.textTheme.subtitle2,
),
],
),
),
),
],
),
);
}).toList();
}
また、コンパイルを試みる前に、build()関数を変更してBuildContextを_buildGridCards()に渡します。
body: GridView.count(
crossAxisCount: 2,
padding: EdgeInsets.all(16.0),
childAspectRatio: 8.0 / 9.0,
children: _buildGridCards(context) // Changed code
),
カード間に垂直方向のスペースが追加されていないことに気付くかもしれません。 これは、デフォルトで、上部と下部に4ポイントのパディングがあるためです。
プロジェクトを保存します。
商品データは表示されますが、画像の周囲に余分なスペースがあります。 画像は、デフォルトでBoxFit.scaleDownで描画されます(この場合)。 これをBoxFit.fitWidthに変更して、少しズームインして余分な空白を削除しましょう。
Imageウィジェットのfit:フィールドを追加して、値にBoxFit.fitWidthを設定します。
私たちの製品は今アプリに完全に表示されています!
ここまでのコード
//home.dart import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; //←追加 import 'model/products_repository.dart'; //←追加 import 'model/product.dart'; //←追加 class HomePage extends StatelessWidget { List<Card> _buildGridCards(BuildContext context) { List<Product> products = ProductsRepository.loadProducts(Category.all); if (products == null || products.isEmpty) { return const <Card>[]; } final ThemeData theme = Theme.of(context); final NumberFormat formatter = NumberFormat.simpleCurrency( locale: Localizations.localeOf(context).toString()); return products.map((product) { return Card( clipBehavior: Clip.antiAlias, // TODO: Adjust card heights (103) child: Column( // TODO: Center items on the card (103) crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ AspectRatio( aspectRatio: 18 / 11, child: Image.asset( product.assetName, package: product.assetPackage, fit: BoxFit.fitWidth, //←最後で追加。 ), ), Expanded( child: Padding( padding: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0), child: Column( // TODO: Align labels to the bottom and center (103) crossAxisAlignment: CrossAxisAlignment.start, // TODO: Change innermost Column (103) children: <Widget>[ // TODO: Handle overflowing labels (103) Text( product.name, style: theme.textTheme.headline6, maxLines: 1, ), SizedBox(height: 8.0), Text( formatter.format(product.price), style: theme.textTheme.subtitle2, ), ], ), ), ), ], ), ); }).toList(); } // TODO: Add a variable for Category (104) @override Widget build(BuildContext context) { // TODO: Return an AsymmetricView (104) // TODO: Pass Category variable to AsymmetricView (104) return Scaffold( appBar:AppBar( leading: IconButton( icon: Icon( Icons.menu, semanticLabel: 'menu', ), onPressed: () { print('Menu button'); }, ), title: Text('SHRINE'), actions: <Widget>[ IconButton( icon: Icon( Icons.search, semanticLabel: 'search', ), onPressed: () { print('Search button'); }, ), IconButton( icon: Icon( Icons.tune, semanticLabel: 'filter', ), onPressed: () { print('Filter button'); }, ), ], ), body: GridView.count( crossAxisCount: 2, padding: EdgeInsets.all(16.0), childAspectRatio: 8.0 / 9.0, // TODO: Build a grid of cards (102) children: _buildGridCards(context), ), resizeToAvoidBottomInset: false, ); } }
7.Recup(要約)
私たちのアプリには、ユーザーをログイン画面からホーム画面に移動する基本的なフローがあり、そこで製品を表示できます。
ほんの数行のコードで、トップアプリバー(タイトルと3つのボタン付き)とカード(アプリのコンテンツを表示するため)を追加しました。 ホーム画面はシンプルで機能的になり、基本的な構造と実用的なコンテンツを備えています。
Next steps
それは完全に機能していますが、私たちのアプリはまだ特定のブランドや視点を表現していません。 MDC-103:色、形、高さ、タイプをテーマにしたマテリアルデザインでは、これらのコンポーネントのスタイルをカスタマイズして、活気に満ちたモダンなブランドを表現します。
参考
https://codelabs.developers.google.com/codelabs/mdc-102-flutter#5