Flutter初心者の学習記録 第17回:Flutter基本ウィジェット – ImageとCard

こんにちは、Flutterエンジニアの皆さん!Flutterアプリ開発において、視覚的に魅力的なUIを作成するために欠かせないのがImageCardウィジェットです。今回は、これらの基本ウィジェットの使い方から応用テクニックまで詳しく解説していきます。

Imageウィジェット:画像表示の基本

基本的な使い方

Imageウィジェットは、アプリに画像を表示するための最も基本的なウィジェットです。

Image.asset('assets/images/sample.jpg')

画像の読み込み方法

Flutterでは、さまざまな方法で画像を読み込むことができます。

アセット画像の読み込み

Image.asset(
  'assets/images/logo.png',
  width: 200,
  height: 100,
)

ネットワーク画像の読み込み

Image.network(
  'https://example.com/image.jpg',
  loadingBuilder: (context, child, loadingProgress) {
    if (loadingProgress == null) return child;
    return const CircularProgressIndicator();
  },
)

ファイルから画像を読み込み

Image.file(File('path/to/image.jpg'))

画像の表示調整

fit プロパティで表示方法を制御

Image.asset(
  'assets/images/photo.jpg',
  fit: BoxFit.cover, // 画像をコンテナに合わせて拡大・縮小
  width: double.infinity,
  height: 200,
)

主要なBoxFitオプション

  • BoxFit.cover:アスペクト比を保持しつつ、コンテナを完全に覆う
  • BoxFit.contain:アスペクト比を保持しつつ、コンテナ内に完全に収める
  • BoxFit.fill:アスペクト比を無視してコンテナを完全に埋める
  • BoxFit.fitWidth:幅に合わせて拡大・縮小

エラーハンドリング

Image.network(
  'https://example.com/image.jpg',
  errorBuilder: (context, error, stackTrace) {
    return const Icon(
      Icons.error,
      color: Colors.red,
      size: 50,
    );
  },
)

Cardウィジェット:マテリアルデザインのカード

基本的な使い方

Cardウィジェットは、マテリアルデザインのカードを簡単に実装できる便利なウィジェットです。

Card(
  child: Padding(
    padding: const EdgeInsets.all(16.0),
    child: Text('これはカードです'),
  ),
)

カードの見た目をカスタマイズ

影の調整

Card(
  elevation: 8.0, // 影の深さ
  shadowColor: Colors.grey.withOpacity(0.5),
  child: Container(
    padding: const EdgeInsets.all(16.0),
    child: Text('影付きカード'),
  ),
)

角の丸み調整

Card(
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(15.0),
  ),
  child: Container(
    padding: const EdgeInsets.all(16.0),
    child: Text('角丸カード'),
  ),
)

カードの色設定

Card(
  color: Colors.lightBlue.shade50,
  child: Container(
    padding: const EdgeInsets.all(16.0),
    child: Text('カラフルカード'),
  ),
)

実践的なカードの使用例

プロフィールカード

Card(
  margin: const EdgeInsets.all(16.0),
  elevation: 4.0,
  child: Padding(
    padding: const EdgeInsets.all(16.0),
    child: Row(
      children: [
        CircleAvatar(
          radius: 30,
          backgroundImage: AssetImage('assets/images/avatar.jpg'),
        ),
        const SizedBox(width: 16),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                '田中太郎',
                style: Theme.of(context).textTheme.titleLarge,
              ),
              const SizedBox(height: 8),
              Text(
                'Flutter開発者',
                style: Theme.of(context).textTheme.bodyMedium,
              ),
            ],
          ),
        ),
      ],
    ),
  ),
)

ImageとCardの組み合わせ

画像付きカードの作成

Card(
  clipBehavior: Clip.antiAlias,
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Image.asset(
        'assets/images/food.jpg',
        height: 200,
        width: double.infinity,
        fit: BoxFit.cover,
      ),
      Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              '美味しい料理',
              style: Theme.of(context).textTheme.titleLarge,
            ),
            const SizedBox(height: 8),
            Text(
              'この料理は地元の新鮮な食材を使用して作られています。',
              style: Theme.of(context).textTheme.bodyMedium,
            ),
          ],
        ),
      ),
    ],
  ),
)

グリッドレイアウトでの活用

GridView.builder(
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    crossAxisSpacing: 8.0,
    mainAxisSpacing: 8.0,
  ),
  itemCount: items.length,
  itemBuilder: (context, index) {
    return Card(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Expanded(
            child: Image.asset(
              items[index].imagePath,
              fit: BoxFit.cover,
              width: double.infinity,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(
              items[index].title,
              style: Theme.of(context).textTheme.titleSmall,
            ),
          ),
        ],
      ),
    );
  },
)

パフォーマンスとベストプラクティス

画像の最適化

適切なサイズの画像を使用

Image.asset(
  'assets/images/thumbnail.jpg',
  width: 100,
  height: 100,
  cacheWidth: 100, // メモリ使用量を削減
  cacheHeight: 100,
)

画像のキャッシュ管理

Image.network(
  imageUrl,
  loadingBuilder: (context, child, loadingProgress) {
    if (loadingProgress == null) return child;
    return SizedBox(
      width: 100,
      height: 100,
      child: CircularProgressIndicator(
        value: loadingProgress.expectedTotalBytes != null
          ? loadingProgress.cumulativeBytesLoaded / 
            loadingProgress.expectedTotalBytes!
          : null,
      ),
    );
  },
)

カードの効率的な使用

不必要な再描画を避ける

class ProductCard extends StatelessWidget {
  final Product product;
  
  const ProductCard({Key? key, required this.product}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Card(
      key: ValueKey(product.id), // 効率的な更新のためのキー
      child: // カードの内容
    );
  }
}

まとめ

ImageとCardウィジェットは、Flutterアプリの見た目を大きく左右する重要なコンポーネントです。基本的な使い方を理解し、適切にカスタマイズすることで、ユーザーにとって魅力的なUIを作成できます。

特に重要なポイント:

  • 画像の読み込み方法とエラーハンドリング
  • カードの視覚的カスタマイズ
  • パフォーマンスを考慮した実装
  • 両者を組み合わせた効果的なレイアウト

継続的な学習で、より良いFlutterアプリを開発していきましょう!

コメントを残す

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