tukutuku
@tukutuku

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

コードを書いているのに、表示されない。

Q&A

Closed

スクリーンショット 2024-10-17 午前10.46.31.png

解決したいこと

アプリ開発初心者でチャットGPTを使ってアプリを作っています。
グループ追加のボタンやテキストなどコードを書いているのにも関わらず、ビルドしても表示されません。どうしたらいいでしょうか?助けてください。

LINEのような個人、グループアカウントを作れるUIを作ってます。

flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';

class GroupPage extends StatefulWidget {
  final Function(String, ImageProvider) onGroupAdded;

  GroupPage({required this.onGroupAdded});

  @override
  _GroupPageState createState() => _GroupPageState();
}

class _GroupPageState extends State<GroupPage> {
  String _accountName = "ユーザー名";  // アカウント名の初期値
  File? _profileImage;  // プロフィール画像を保存する変数

  List<Map<String, dynamic>> _friendsList = [];
  List<Map<String, dynamic>> _groupsList = []; // 追加されたグループのリスト
  List<int> _selectedFriendsForGroup = []; // グループ作成用に選択された友達のインデックス

  Future<void> _pickImage() async {
    final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      setState(() {
        _profileImage = File(pickedFile.path);
      });
    }
  }

  Future<File?> _pickGroupImage() async {
    final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
    if (pickedFile != null) {
      return File(pickedFile.path);
    }
    return null;
  }

  void _editProfile() {
    TextEditingController _controller = TextEditingController(text: _accountName);

    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      builder: (BuildContext context) {
        return Padding(
          padding: EdgeInsets.only(
            bottom: MediaQuery.of(context).viewInsets.bottom,
          ),
          child: Container(
            height: MediaQuery.of(context).size.height * 0.9,
            padding: EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Center(
                  child: GestureDetector(
                    onTap: _pickImage,
                    child: CircleAvatar(
                      radius: 50,
                      backgroundImage: _profileImage != null
                          ? FileImage(_profileImage!)
                          : AssetImage('assets/profile_placeholder.png') as ImageProvider,
                    ),
                  ),
                ),
                SizedBox(height: 12),
                Text('アカウント名', style: TextStyle(fontSize: 16)),
                TextField(
                  controller: _controller,
                  autofocus: true,
                  decoration: InputDecoration(hintText: "新しいアカウント名を入力"),
                ),
                SizedBox(height: 12),
                Center(
                  child: ElevatedButton(
                    onPressed: () {
                      setState(() {
                        _accountName = _controller.text;
                      });
                      Navigator.of(context).pop();
                    },
                    child: Text('保存'),
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  void _addFriend() {
    setState(() {
      _friendsList.add({
        'name': '友達 ${_friendsList.length + 1}',
        'image': AssetImage('assets/profile_placeholder.png'),
      });
    });
  }

  void _deleteFriend(int index) {
    setState(() {
      _friendsList.removeAt(index);
    });
  }

  void _createGroup() {
    _selectedFriendsForGroup.clear();
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            return AlertDialog(
              title: Text('グループに追加する友達を選択'),
              content: Container(
                width: double.maxFinite,
                height: 300,
                child: ListView.builder(
                  itemCount: _friendsList.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      leading: CircleAvatar(
                        radius: 20,
                        backgroundImage: _friendsList[index]['image'] is File
                            ? FileImage(_friendsList[index]['image'])
                            : _friendsList[index]['image'] as ImageProvider,
                      ),
                      title: Text(_friendsList[index]['name']),
                      trailing: Checkbox(
                        value: _selectedFriendsForGroup.contains(index),
                        onChanged: (bool? selected) {
                          setState(() {
                            if (selected == true) {
                              _selectedFriendsForGroup.add(index);
                            } else {
                              _selectedFriendsForGroup.remove(index);
                            }
                          });
                        },
                      ),
                    );
                  },
                ),
              ),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text('キャンセル'),
                ),
                TextButton(
                  onPressed: () {
                    if (_selectedFriendsForGroup.isNotEmpty) {
                      Navigator.of(context).pop();
                      _showGroupNameAndImageDialog();
                    }
                  },
                  child: Text('OK'),
                ),
              ],
            );
          },
        );
      },
    );
  }

  void _showGroupNameAndImageDialog() {
    TextEditingController groupNameController = TextEditingController();
    File? groupProfileImage;

    showDialog(
      context: context,
      builder: (BuildContext context) {
        return Padding(
          padding: EdgeInsets.only(
            bottom: MediaQuery.of(context).viewInsets.bottom,
          ),
          child: StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
              return AlertDialog(
                title: Text('グループ名と画像を設定してください'),
                content: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    GestureDetector(
                      onTap: () async {
                        groupProfileImage = await _pickGroupImage();
                        setState(() {});
                      },
                      child: CircleAvatar(
                        radius: 40,
                        backgroundImage: groupProfileImage != null
                            ? FileImage(groupProfileImage!)
                            : AssetImage('assets/profile_placeholder.png') as ImageProvider,
                      ),
                    ),
                    SizedBox(height: 16),
                    TextField(
                      controller: groupNameController,
                      autofocus: true,
                      decoration: InputDecoration(hintText: 'グループ名を入力'),
                    ),
                  ],
                ),
                actions: [
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                    child: Text('キャンセル'),
                  ),
                  TextButton(
                    onPressed: () {
                      if (groupNameController.text.isNotEmpty) {
                        List<Map<String, dynamic>> selectedFriends = _selectedFriendsForGroup
                            .map((index) => _friendsList[index])
                            .toList();

                        setState(() {
                          _groupsList.add({
                            'name': groupNameController.text,
                            'members': selectedFriends,
                            'image': groupProfileImage ?? AssetImage('assets/profile_placeholder.png'),
                          });
                        });

                        widget.onGroupAdded(
                          groupNameController.text,
                          groupProfileImage != null
                              ? FileImage(groupProfileImage!)
                              : AssetImage('assets/profile_placeholder.png'),
                        );

                        Navigator.of(context).pop();
                      }
                    },
                    child: Text('作成'),
                  ),
                ],
              );
            },
          ),
        );
      },
    );
  }

  void _showGroupMembersWithDeleteDialog(int groupIndex) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('グループメンバー'),
          content: Container(
            width: double.maxFinite,
            height: 300,
            child: ListView.builder(
              itemCount: _groupsList[groupIndex]['members'].length,
              itemBuilder: (context, index) {
                return ListTile(
                  leading: CircleAvatar(
                    radius: 20,
                    backgroundImage: _groupsList[groupIndex]['members'][index]['image'] is File
                        ? FileImage(_groupsList[groupIndex]['members'][index]['image'])
                        : _groupsList[groupIndex]['members'][index]['image'] as ImageProvider,
                  ),
                  title: Text(_groupsList[groupIndex]['members'][index]['name']),
                );
              },
            ),
          ),
          actions: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                TextButton(
                  onPressed: () {
                    setState(() {
                      _groupsList.removeAt(groupIndex);
                    });
                    Navigator.of(context).pop();
                  },
                  child: Text('削除', style: TextStyle(color: Colors.red)),
                ),
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text('支払いへ'),
                ),
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text('閉じる'),
                ),
              ],
            ),
          ],
        );
      },
    );
  }

  void _showFriendProfile(int index) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('プロフィール'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              CircleAvatar(
                radius: 50,
                backgroundImage: _friendsList[index]['image'] is File
                    ? FileImage(_friendsList[index]['image'])
                    : _friendsList[index]['image'] as ImageProvider,
              ),
              SizedBox(height: 16),
              Text(
                _friendsList[index]['name'],
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),
            ],
          ),
                    actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('閉じる'),
            ),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    double buttonDiameter = 80;  // ボタンの直径を少し小さく変更

    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(  // 全体を縦スクロール可能に
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16.0),  // 左右の余白を調整
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Divider(color: Colors.grey.shade300, thickness: 1),
                SizedBox(height: 30),
                // プロフィール表示
                Row(
                  children: [
                    CircleAvatar(
                      radius: 30,
                      backgroundImage: _profileImage != null
                          ? FileImage(_profileImage!)
                          : AssetImage('assets/profile_placeholder.png') as ImageProvider,
                    ),
                    SizedBox(width: 12),
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          _accountName, 
                          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)
                        ),
                        TextButton(
                          onPressed: _editProfile,
                          child: Text('プロフィールを編集'),
                        ),
                      ],
                    ),
                  ],
                ),
                SizedBox(height: 30),
                // 友達追加ボタンと友達の人数を表示
                Row(
                  children: [
                    Column(
                      children: [
                        ElevatedButton(
                          onPressed: _addFriend,
                          style: ElevatedButton.styleFrom(
                            shape: CircleBorder(),
                            padding: EdgeInsets.all(20),  // ボタンを小さく
                          ),
                          child: Text('+', style: TextStyle(fontSize: 35)),  // アイコンも小さく調整
                        ),
                        SizedBox(height: 8),
                        Container(
                          width: buttonDiameter,
                          alignment: Alignment.center,
                          child: Text(
                            '友達追加',
                            style: TextStyle(fontSize: 12),
                          ),
                        ),
                      ],
                    ),
                    Spacer(),
                    Text(
                      '友達: ${_friendsList.length}人',  // 友達の人数を表示
                      style: TextStyle(fontSize: 16),
                    ),
                  ],
                ),
                SizedBox(height: 30),
                // 友達リストの表示
                GridView.builder(
                  physics: NeverScrollableScrollPhysics(),
                  shrinkWrap: true,
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 4,  // 一行に最大4つの要素を表示
                    childAspectRatio: 1,  // 正方形
                    mainAxisSpacing: 10,  // 上下間のスペース
                    crossAxisSpacing: 10,  // 左右間のスペース
                  ),
                  itemCount: _friendsList.length,
                  itemBuilder: (context, index) {
                    return GestureDetector(
                      onTap: () {
                        _showFriendProfile(index);  // 友達のプロフィールを表示する関数を呼び出す
                      },
                      onLongPress: () {
                        showDialog(
                          context: context,
                          builder: (BuildContext context) {
                            return AlertDialog(
                              title: Text('友達を削除しますか?'),
                              actions: [
                                TextButton(
                                  onPressed: () {
                                    Navigator.of(context).pop();
                                  },
                                  child: Text('キャンセル'),
                                ),
                                TextButton(
                                  onPressed: () {
                                    _deleteFriend(index);
                                    Navigator.of(context).pop();
                                  },
                                  child: Text('削除'),
                                ),
                              ],
                            );
                          },
                        );
                      },
                      child: Column(
                        children: [
                          CircleAvatar(
                            radius: 25,  // プロフィール画像を小さく
                            backgroundImage: _friendsList[index]['image'] is File
                                ? FileImage(_friendsList[index]['image'])
                                : _friendsList[index]['image'] as ImageProvider,
                          ),
                          SizedBox(height: 5),
                          Text(
                            _friendsList[index]['name'],
                            style: TextStyle(fontSize: 10),
                          ),
                        ],
                      ),
                    );
                  },
                ),
                SizedBox(height: 30),
                // グレーのライン
                Divider(color: Colors.grey.shade400, thickness: 1),
                SizedBox(height: 20),
                // グループ追加ボタンとグループ数を表示
                Row(
                  children: [
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: [
                        ElevatedButton(
                          onPressed: _createGroup,  // グループ作成ダイアログを表示
                          style: ElevatedButton.styleFrom(
                            shape: CircleBorder(),
                            padding: EdgeInsets.all(20),
                          ),
                          child: Text('+', style: TextStyle(fontSize: 35)),
                        ),
                        SizedBox(height: 8),
                        Container(
                          width: buttonDiameter,
                          alignment: Alignment.center,
                          child: Text(
                            'グループ追加',
                            style: TextStyle(fontSize: 12),
                          ),
                        ),
                      ],
                    ),
                    Spacer(),
                    Text(
                      'グループ: ${_groupsList.length}個',  // グループ数を表示
                      style: TextStyle(fontSize: 16),
                    ),
                  ],
                ),
                SizedBox(height: 30),
                // グループリストの表示
                GridView.builder(
                  physics: NeverScrollableScrollPhysics(),
                  shrinkWrap: true,
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 4,
                    childAspectRatio: 1,
                    mainAxisSpacing: 10,
                    crossAxisSpacing: 10,
                  ),
                  itemCount: _groupsList.length,
                  itemBuilder: (context, index) {
                    if (_groupsList[index]['members'].isNotEmpty) {
                      return GestureDetector(
                        onTap: () {
                          _showGroupMembersWithDeleteDialog(index);
                        },
                        child: Column(
                          children: [
                            CircleAvatar(
                              radius: 25,
                              backgroundImage: _groupsList[index]['image'] is File
                                  ? FileImage(_groupsList[index]['image'])
                                  : _groupsList[index]['image'] as ImageProvider,
                            ),
                            SizedBox(height: 5),
                            Text(
                              _groupsList[index]['name'],
                              style: TextStyle(fontSize: 10),
                            ),
                          ],
                        ),
                      );
                    } else {
                      return Container();  // メンバーがいないグループは表示しない
                    }
                  },
                ),
                SizedBox(height: 30),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
0

4Answer

質問文からだと「どのようモノを」「どのような構成で」作られてるのか分からないので、的はずれな回答になっておりましたら申し訳ございません...!

おそらく下記がないからではないでしょうか。
1.プロジェクトを実行させるmain関数
2.画面を構成するclassの呼び出し

main.dartで下記の記述を改めて確認してみてください!

//main.dart

//1.のプロジェクトを実行させるmain関数
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
      ),
      home:MyHomePage(),//最初の起動画面 ※2.画面を構成するクラスの呼び出しに該当
    );
  }
}

「home:MyHomePage()」で「class MyHomePage extends StatefulWidget」を呼び出し、アプリのルートページとして表示させています。

とりあえず画面が表示できない問題を解消するだけであれば、MyHomePageをGroupePageに置き換えれば表示できるはずです。
※コード拝見する感じ、requiredで引数が要求されているので単に置き換えるだけだと「引数が渡っていない」ってエラーになるかと...一旦削除するなど上手く調整してみて画面が表示されるかを、まず確認してみてください!

下記ページ等参考になるかと思います。
https://zenn.dev/nyarufoy/articles/e0bc5442e887ac

今後画面遷移を実現したい場合は、NavigationやRoutingで調べると色々出てくるかと思います!

ご健闘お祈りしています!

1Like

コードの一番外側だけ ``` で囲っていいただけませんか?うまくコード表示になってくれていない箇所がある為

0Like

Comments

  1. @tukutuku

    Questioner

    しました。お願いします

ビルドしても表示されません。

これはビルドが成功したが 何も表示されない意なのか、それともエラーが出ているが エラーが読めない為気にしていないのかどっちでしょうか?それとも結果がなんか出ているが、それがエラーかどうかわからないのでしょうか?

0Like

Comments

  1. もしもエラーが出ているのであれば その内容を 質問文に含めてください。

  2. @tukutuku

    Questioner

    エラーは出てません。

  3. ビルド結果は実行できていますでしょうか?

  4. @tukutuku

    Questioner

    スクリーンショット 2024-10-17 午後0.03.23.png
    実行できています。

長いソースなので可能な限りインデントがあると他の回答者さんも回答がしやすいかと思います。
AndroidStudioを使用しているのかVScodeを使用しているのかでも回答が変わるかもしれないので、実行環境や、画面のスクリーンショットを貼るとより早く回答を得られると思います。
コードとして変なことはなかったように思うので@Madao_2306さんと同じような回答になります。

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'タイトル',
      home: GroupPage(
        onGroupAdded: (String groupName, ImageProvider image) {
          // コールバック処理を追加
        },
      ),
    );
  }
}

また、以下のようにある程度Widget型のメソッドで切り出すと原因の切り分けがしやすいと思います。

 @override
  Widget build(BuildContext context) {
    double buttonDiameter = 80; // ボタンの直径を少し小さく変更

    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView( // 全体を縦スクロール可能に
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16.0), 
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _Divider(color: Colors.grey.shade300, thickness: 1),
                SizedBox(height: 30),
                _buildProfileSection(), 
                SizedBox(height: 30),
                _buildFriendAddSection(buttonDiameter),
                SizedBox(height: 30),
                _buildFriendList(), 
                SizedBox(height: 30),
                _Divider(color: Colors.grey.shade400, thickness: 1),
                SizedBox(height: 20),
                _buildGroupAddSection(buttonDiameter),
                SizedBox(height: 30),
                _buildGroupList(), 
                SizedBox(height: 30),
              ],
            ),
          ),
        ),
      ),
    );
  }
// 例として一つWidget型のメソッドで切り出す
  Widget _buildProfileSection() {
    return Row(
      children: [
        CircleAvatar(
          radius: 30,
          backgroundImage: _profileImage != null
              ? FileImage(_profileImage!)
              : AssetImage('assets/profile_placeholder.png') as ImageProvider,
        ),
        SizedBox(width: 12),
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(_accountName, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            TextButton(
              onPressed: _editProfile,
              child: Text('プロフィールを編集'),
            ),
          ],
        ),
      ],
    );
  }
0Like

Comments

  1. @tukutuku

    Questioner

    スクリーンショットを貼りました。
    みてください

  2. みました、ありがとうございます。
    ログにRenderflexErrorとか出ていないですか?ログから得られる情報からもう少しわかることはないでしょうか?
    Buildができている≒エラーがないではなく、
    Flutterの場合は画面として表示するときにサイズが決まらないと無限に大きくなろうとするWidget(GridView.builderやListView.builder)などがあるのでそのあたり調べてみてください。

Your answer might help someone💌