2020/10/31 MDC-102 Flutter: Material Structure and Layout (Flutter)の訳パート4

 

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です