[flutter/dart] ListView, AlertDialog 데이터 추가 시 화면에 나타내기

yevvon·2024년 1월 9일
0

flutter

목록 보기
6/12

버튼을 누르면 팝업창이 나타나고 팝업창에 정보를 입력하면 화면에 계속 쌓이는 코드를 짜보겠습니다.

먼저 팝업창을 띄울 버튼을 만들어 줍니다.

ElevatedButton(
                  style: ElevatedButton.styleFrom(
                      elevation: 0.0,
                      backgroundColor: Colors.blueGrey,
                      minimumSize: Size(150, 30)),
                  onPressed: () {
                    _showDialog(context);
                  },
                  child: Text('팝업',
                      style: TextStyle(
                          color: Colors.black,
                          fontSize: 20,
        )
    )
),

onpressed에 있는 _showDialog를 이름으로 하는 팝업창 함수를 만들어 보겠습니다.

팝업창은 AlertDialog를 사용해서 만들어 주겠습니다.

먼저 팝업창에서 textfeild에서 받을 정보를 저장할 변수가 필요합니다.

final _todoEditController = TextEditingController();
final _dateEditController = TextEditingController();

그리고 저장할 데이터를 담을 리스트를 만들어 줍니다.

final List<String> todo = ["할일1"];
final List<String> date = ["날짜1"];

다음으로는 팝업창을 만들어 보겠습니다.

AlertDialog(
          title: Text("팝업창",
            style: TextStyle(color: Color(0xFF7D5A50),),
          ),
          content: Column(
            children: [
              TextField(
                maxLength: 20,
                decoration: InputDecoration(
                  hintText: '할일',
                  enabledBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                  focusedBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                ),
                controller: _questionEditController,
              ),
              TextField(
                maxLength: 20,
                decoration: InputDecoration(
                  hintText: '날짜',
                  enabledBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                  focusedBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                ),
                controller: _answerEditController,
              ),
            ],
          ),
          actions: <Widget>[
            ElevatedButton(
                style: ElevatedButton.styleFrom(
                    elevation: 0.0,
                    backgroundColor: Color(0x4D968C83),
                    minimumSize: Size(150, 30)),
                onPressed: () => Navigator.of(context).pop(),
                child: Text('취소',
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: 20,)
                )
            ),
            ElevatedButton(
                style: ElevatedButton.styleFrom(
                    elevation: 0.0,
                    backgroundColor: Color(0xFF7D5A50),
                    minimumSize: Size(150, 30)),
                onPressed: () {
                  setState(() {
                    String questionText = _questionEditController.text;
                    String answerText = _answerEditController.text;
                    question.add(questionText);
                    answer.add(answerText);
                  });
                  Navigator.of(context).pop();
                },
                child: Text('확인',
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: 20,)
                )
            ),
          ],
        );

textfield를 두 개 사용하여 할 일을 적는 칸과 날짜를 적는 칸을 만들어줍니다.

다음으로는 actions에 elevatedbutton을 두 개 만들어 확인 버튼과 취소 버튼을 만들어 주었습니다.

취소 버튼에는 onPressed: () => Navigator.of(context).pop(), 을 사용하여 팝업창이 닫히는 기능을 구현해 주었고

확인 버튼에는 setState를 통해 텍스트 필드에서 작성한 데이터를 변수에 저장하고 변수를 다시 리스트에 넣어주는 작업을 하였습니다.

setState(() {
                    String todoText = _questionEditController.text;
                    String dateText = _answerEditController.text;
                    todo.add(todoText);
                    date.add(dateText);
                  });

화면에 나타나는 컨테이너는 커스텀 컨테이너를 활용하였습니다.

class TodoData {
  final String todo;
  final String date;

  TodoData({
    required this.todo,
    required this.date,
  });
}

컨테이너에서 필요한 변수들을 설정해 줍니다.

class CustomContainer extends StatelessWidget {
  final String vtodo;
  final String vdate;

  CustomContainer({super.key,
    required this.vtodo,
    required this.vdate,
  });

  @override
  Widget build(BuildContext context) {
    final SizeX = MediaQuery.of(context).size.width;
    final SizeY = MediaQuery.of(context).size.height;

    return Container(
      margin: EdgeInsets.fromLTRB(0, 20, 0, 0),
      height: SizeY*0.08,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.all(Radius.circular(10)),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Row(
            children: [
              SizedBox(
                width: 25,
              ),
              Text(
                vtodo,
                style: TextStyle(
                    fontSize: 17,
                    color: Color(0xFF7D5A50)),
              ),
            ],
          ),
          Container(
            color: Colors.grey,
            width: SizeX*0.8, height: 1,
            margin: EdgeInsets.fromLTRB(0, 5, 0, 6),
          ),//칸 나누는 줄
          Row(
            children: [
              SizedBox(
                width: 30,
              ),
              Text(vdate,
                  style: TextStyle(
                    fontSize: 17,
                  ))
            ],
          ),
        ],
      ),
    );
  }
}


이렇게 생긴 컨테이너를 디자인해 주었습니다.

이제 본문에 팝업창과 컨테이너를 이어주기만 하면 됩니다.

데이터가 쌓일 때마다 화면에 컨테이너가 계속 쌓이도록 ListView.builder를 사용해 주겠습니다.

Expanded(
              child: ListView.builder(
                itemCount: todo.length,
                  itemBuilder: (BuildContext context, int index){
                    return CustomContainer(
                        vtodo: todo[index],
                        vdate: date[index]
                    );
                  }
              ),
            ),

todo 리스트에 쌓인 개수만큼 컨테이너가 쌓이게 하기 위해

itmeCount: todo.length,로 개수를 제한해 주었습니다

그리고 아까 만들어 둔 커스텀 컨테이너를 return 하여 불러주고

커스텀 컨테이너에 팝업에서 받아온 정보를 넘겨줍니다.

이 화면에서 팝업 버튼을 누르면

팝업창이 뜨고 텍스트 필드에 각각 데이터를 입력하고 확인 버튼을 누르면

화면에 데이터가 추가됩니다.

전체코드

import 'package:flutter/material.dart';

class second extends StatefulWidget {
  const second({super.key});

  @override
  State<second> createState() => _secondState();
}

final _questionEditController = TextEditingController();
final _answerEditController = TextEditingController();

class _secondState extends State<second> {
  final List<String> todo = ["할일1"];
  final List<String> date = ["날짜1"];

  Future<void> _showDialog(BuildContext context) {

    return showDialog<void>(
      context: context,
      barrierDismissible: false,

      builder: (BuildContext context) {
        return AlertDialog(
          title: Text("팝업창",
            style: TextStyle(color: Color(0xFF7D5A50),),
          ),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              TextField(
                maxLength: 20,
                decoration: InputDecoration(
                  hintText: '할일',
                  enabledBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                  focusedBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                ),
                controller: _questionEditController,
              ),
              TextField(
                maxLength: 20,
                decoration: InputDecoration(
                  hintText: '날짜',
                  enabledBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                  focusedBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.black54,),
                  ),
                ),
                controller: _answerEditController,
              ),
            ],
          ),
          actions: <Widget>[
            ElevatedButton(
                style: ElevatedButton.styleFrom(
                    elevation: 0.0,
                    backgroundColor: Color(0x4D968C83),
                    minimumSize: Size(150, 30)),
                onPressed: () => Navigator.of(context).pop(),
                child: Text('취소',
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: 20,)
                )
            ),
            ElevatedButton(
                style: ElevatedButton.styleFrom(
                    elevation: 0.0,
                    backgroundColor: Color(0xFF7D5A50),
                    minimumSize: Size(150, 30)),
                onPressed: () {
                  setState(() {
                    String questionText = _questionEditController.text;
                    String answerText = _answerEditController.text;
                    todo.add(questionText);
                    date.add(answerText);
                  });
                  Navigator.of(context).pop();
                },
                child: Text('확인',
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: 20,)
                )
            ),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black12,
      body: Center(
        child: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: todo.length,
                  itemBuilder: (BuildContext context, int index){
                    return CustomContainer(
                        vtodo: todo[index],
                        vdate: date[index]
                    );
                  }
              ),
            ),
            Container(
              child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                      elevation: 0.0,
                      backgroundColor: Colors.blueGrey,
                      minimumSize: Size(150, 30)),
                  onPressed: () {
                    _showDialog(context);
                  },
                  child: Text('팝업',
                      style: TextStyle(
                          color: Colors.black,
                          fontSize: 20,))),
            )
          ],
        ),
      ),
    );
  }
}

class TodoData {
  final String todo;
  final String date;

  TodoData({
    required this.todo,
    required this.date,
  });
}

class CustomContainer extends StatelessWidget {
  final String vtodo;
  final String vdate;

  CustomContainer({super.key,
    required this.vtodo,
    required this.vdate,
  });

  @override
  Widget build(BuildContext context) {
    final SizeX = MediaQuery.of(context).size.width;
    final SizeY = MediaQuery.of(context).size.height;

    return Container(
      margin: EdgeInsets.fromLTRB(0, 20, 0, 0),
      height: SizeY*0.08,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.all(Radius.circular(10)),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Row(
            children: [
              SizedBox(
                width: 25,
              ),
              Text(
                vtodo,
                style: TextStyle(
                    fontSize: 17,
                    color: Color(0xFF7D5A50)),
              ),
            ],
          ),
          Container(
            color: Colors.grey,
            width: SizeX*0.8, height: 1,
            margin: EdgeInsets.fromLTRB(0, 5, 0, 6),
          ),//칸 나누는 줄
          Row(
            children: [
              SizedBox(
                width: 30,
              ),
              Text(vdate,
                  style: TextStyle(
                    fontSize: 17,
                  ))
            ],
          ),
        ],
      ),
    );
  }
}

0개의 댓글

관련 채용 정보