@Akira4989

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Flutter(Dart)で画像をグリッド表示したいのですが、for...inでエラーになり、forEachに変更してもエラー。

初めて投稿します。
Flutter(Dart)を始めて3日目になります。

実現したいこと

スマホアプリでアプリ内に保存しているjpg画像をInstagramのようにグリッド表示し、タップされた画像を画面に合わせて表示できるようにしたいと考えています。

直したいこと

Android Studioを使ってFlutter(Dart)で上記のようなアプリを作ってみたく、見よう見まねでコードを書いてみたのですが、下記のエラーが消えず悩んでいます。

発生している問題・エラーメッセージ

コーディングしているエリアの右上のエラーとワーニングの数が表示されているところを押してみると、ソースの下に下記の3つのエラーが出ます。

Function expressions can't be named. :23
Expected an identifier. :23
The getter '(' isn't defined for the type 'Future<List<String>>'. :23

デバッグボタンを押して実行してみると下記のエラーになります。

lib/griddisplay_images.dart:23:26: Error: A function expression can't have a name.
            fileNameList.forEach(imageFileName) {
                         ^^^^^^^
lib/griddisplay_images.dart:23:26: Error: Expected an identifier, but got 'forEach'.
Try inserting an identifier before 'forEach'.
            fileNameList.forEach(imageFileName) {
                         ^^^^^^^
Target kernel_snapshot failed: Exception


FAILURE: Build failed with an exception.

該当のソースコード

import 'dart:io';

import 'package:flutter/material.dart';

class GridImagesPage extends StatelessWidget {
  const GridImagesPage({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Future<List<String>> fileNameList = getFileList();
    return Scaffold(
      appBar: AppBar(
        title: const Text('画像をタップしてください'),
      ),
      body: GridView.count(
          crossAxisCount: 3,
          childAspectRatio: 1.5,
          mainAxisSpacing: 4,
          crossAxisSpacing: 4,
          children: [
            fileNameList.forEach(imageFileName) {
              //for (var imageFileName in fileNameList)
              Hero(
                tag: Text(imageFileName),
                child: GestureDetector(
                  onTap: () {
                    Navigator.of(context).push(
                      MaterialPageRoute<void>(
                        builder: (context) =>
                            ImagePage(
                              imageFile: imageFileName,
                            ),
                      ),
                    );
                  },
                ),
              );
            }
          ]),
    );
  }

  Future<List<String>> getFileList() async {
    Directory imageFileDir = Directory('images/');
    List<String> fileNameList = [];
    await for (var entity
        in imageFileDir.list(recursive: false, followLinks: false)) {
      fileNameList.add(entity.path);
    }
    return fileNameList;
  }
}

class ImagePage extends StatelessWidget {
  const ImagePage({
    required this.imageFile,
    Key? key,
  }) : super(key: key);
  final String imageFile;

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Scaffold(
        backgroundColor: Colors.black87,
        appBar: AppBar(
          title: Text(imageFile),
          leading: BackButton(
            color: Colors.white,
          ),
        ),
        body: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16),
          child: Hero(
            tag: Text(imageFile),
            child: Center(child: Image.asset(imageFile)),
          ),
        ),
      ),
    );
  }
}

試したこと

元々は、24行目にコメントアウトしていますが、for...inでループさせようとしたのですが、下記のエラーが出て色々と調べていたところforEachでのループを試して見ることにしました。

for...inでのエラー
The type 'Future<List<String>>' used in the 'for' loop must implement 'Iterable'.` :24

補足情報(FW/ツールのバージョンなど)

Android Studio Giraffe | 2022.3.1 Patch 3
Flutter 3.13.9

対処方法がお分かりになられる方がいりゃっしゃいましたら何卒お教えいただけますようお願い致します。

0 likes

2Answer

Comments

  1. @Akira4989

    Questioner

    ありがとうございます。
    Listでないと、サジェストにもforEachの候補が出てこないので、どうすればListにできるか悩んでいました。

forEach に関数を渡していないことに加えて、fileNameList は Future であり List では無いこともエラーの原因だと思います。
for...in でループさせようとしたときにエラーになった要因も fileNameList が List ではなく Future だからだと思います。
以下のようにすればエラーは解消されました(動作確認はしていないので想定された挙動をするかは分かりません)。

  @override
  Widget build(BuildContext context) {
    Future<List<String>> fileNameList = getFileList();
+    List<Widget> heroes = [];
+    fileNameList.then((list) => list.forEach((imageFileName) {
+      heroes.add(Hero(
+        tag: Text(imageFileName),
+        child: GestureDetector(
+          onTap: () {
+            Navigator.of(context).push(
+              MaterialPageRoute<void>(
+                builder: (context) =>
+                    ImagePage(
+                      imageFile: imageFileName,
+                    ),
+              ),
+            );
+          },
+        ),
+      ));
+    }));
    return Scaffold(
      appBar: AppBar(
        title: const Text('画像をタップしてください'),
      ),
      body: GridView.count(
          crossAxisCount: 3,
          childAspectRatio: 1.5,
          mainAxisSpacing: 4,
          crossAxisSpacing: 4,
+          children: heroes,
-          children: [
-            fileNameList.forEach(imageFileName) {
-              //for (var imageFileName in fileNameList)
-              Hero(
-                tag: Text(imageFileName),
-                child: GestureDetector(
-                  onTap: () {
-                    Navigator.of(context).push(
-                      MaterialPageRoute<void>(
-                        builder: (context) =>
-                            ImagePage(
-                              imageFile: imageFileName,
-                            ),
-                      ),
-                    );
-                  },
-                ),
-              );
-            }
-          ]),
+      )
    );
  }
0Like

Comments

  1. @Akira4989

    Questioner

    ありがとうございます!
    考えていた挙動にはまだなっていませんが、少し先に進めたと思っています。
    ウィジェットをループで作っていけばいいのですね。
    大変参考になりました。

Your answer might help someone💌