리스트에 아이템을 추가로 등록하는 기능을 만들어보았다.
이전 프로젝트에 이어서 진행하였다.
secondPage.dart의 SecondApp 클래스에 해당 기능을 구현하였다.
먼저 FirstApp 클래스와 같게 list를 받도록 secondPage.dart와 main.dart를 수정하였다.
// secondPage.dart
import 'package:flutter/material.dart';
import 'package:listview_example/animalItem.dart';
class SecondApp extends StatelessWidget {
final List<Animal>? list;
SecondApp({Key? key, this.list}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Text('두 번째 페이지'),
),
),
);
}
}
// main.dart
...
body: TabBarView(
children: <Widget>[FirstApp(list: animalList), SecondApp(list: animalList)],
controller: tabController,
),
...
그 후 SecondApp이 StatefulWidget을 상속하도록 만들었고, createState()에서 반환할 State를 상속한 _SecondApp 클래스를 만들었다.
class SecondApp extends StatefulWidget {
final List<Animal>? list;
SecondApp({Key? key, this.list}) : super(key: key);
State createState() => _SecondApp();
}
class _SecondApp extends State<SecondApp> {
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
),
),
),
);
}
}
dart에서는 반환값을 한 줄로 표현하고자 할 때 => 화살표를 이용할 수 있다.
State createState() => _SecondApp();
children: <Widget>[] 배열 안에 동물 이름을 입력할 텍스트 필드를 추가했다.
class _SecondApp extends State<SecondApp> {
final nameController = TextEditingController();
...
children: <Widget>[
TextField(
controller: nameController,
keyboardType: TextInputType.text,
maxLines: 1,
)
],
),
...
keyboardType으로 키보드 유형을 text로 설정하였고,
controller로 final로 선언한 nameController를 설정하였다.
라디오 버튼을 이용해 동물의 종류를 선택할 수 있도록 코드를 추가하였다.
class _SecondApp extends State<SecondApp> {
final nameController = TextEditingController();
int? _radioValue = 0;
...
children: <Widget>[
TextField( ... ),
Row(
children: <Widget>[
Radio(
value: 0,
groupValue: _radioValue,
onChanged: _radioChange),
Text('양서류'),
Radio(
value: 1,
groupValue: _radioValue,
onChanged: _radioChange),
Text('파충류'),
Radio(
value: 2,
groupValue: _radioValue,
onChanged: _radioChange),
Text('포유류'),
],
)
],
...
_radioChange(int? value) {
setState(() {
_radioValue = value;
});
}
}
각 위젯이 가로로 배치되도록 Row안에 작성하였다.
value는 인덱스 값이다. 각각 0, 1, 2를 넣어 인덱스를 부여했다.
groupValue는 그룹화를 담당한다. int형인 _radioValue를 선언하여 넣었다.
onChanged는 이벤트 처리를 담당한다. _radioChange() 함수를 정의하여 넣었다.
동물이 날 수 있는지 선택하는 체크박스를 추가하였다.
class _SecondApp extends State<SecondApp> {
final nameController = TextEditingController();
int? _radioValue = 0;
bool? flyExist = false;
...
children: <Widget>[
TextField( ... ),
Row( ... ),
Row(
children: <Widget>[
Text('날 수 있나요?'),
Checkbox(
value: flyExist,
onChanged: (bool? check) {
setState(() {
flyExist = check;
});
})
],
)
],
...
동물 이미지를 고를 수 있도록 만들었다.
이미지를 클릭하면 해당 이미지를 선택하도록 만들었다.
class _SecondApp extends State<SecondApp> {
final nameController = TextEditingController();
int? _radioValue = 0;
bool? flyExist = false;
String? _imagePath;
...
children: <Widget>[
TextField( ... ),
Row( ... ),
Row( ... ),
Row(
children: <Widget>[
GestureDetector(
child: Image.asset(
'repo/images/cow.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/cow.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/fox.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/fox.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/bee.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/bee.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/cat.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/cat.png';
},
),
],
)
],
Row 위젯은 이미지가 화면을 벗어나면 다 표시하지 못한다. 그래서 지금은 이미지를 4개만 넣었다.
이를 리스트뷰를 사용하면 이미지를 더 넣을 수 있다.
리스트뷰의 scrollDirection을 사용하면 스크롤 방향을 정할 수 있다.
Row로 만든 이미지 선택 영역을 가로 리스트로 변경하고, 동물들을 추가하였다.
children: <Widget>[
TextField( ... ),
Row( ... ),
Row( ... ),
Container(
height: 100,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
GestureDetector(
child: Image.asset(
'repo/images/cow.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/cow.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/fox.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/fox.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/bee.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/bee.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/cat.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/cat.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/pig.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/pig.png';
},
),
GestureDetector(
child: Image.asset(
'repo/images/wolf.png',
width: 80,
),
onTap: () {
_imagePath = 'repo/images/wolf.png';
},
),
],
),
)
],
위젯들을 양쪽 여백 사이에 균일하게 배치하기 위해 각 Row마다 mainAxisAlignment: MainAxisAlignment.spaceAround를 추가하였다.
children: <Widget>[
TextField(
controller: nameController,
keyboardType: TextInputType.text,
maxLines: 1,
),
Row(
children: <Widget>[ ... ],
mainAxisAlignment: MainAxisAlignment.spaceAround),
Row(
children: <Widget>[ ... ],
mainAxisAlignment: MainAxisAlignment.spaceAround),
Container( ... )
],
동물을 목록에 추가하는 버튼을 만들었다.
버튼을 누르면 추가하기 전에 알람 창을 띄우고 확인을 누르면 동물이 추가되도록 만들었다.
children: <Widget>[
TextField( ... ),
Row( ... ),
Row( ... ),
Container( ... ),
ElevatedButton(
onPressed: () {
var animal = Animal(
animalName: nameController.value.text,
kind: getKind(_radioValue),
imagePath: _imagePath,
flyExist: flyExist);
AlertDialog dialog = AlertDialog(
title: Text('동물 추가하기'),
content: Text(
'이 동물은 ${animal.animalName} 입니다. '
'동물의 종류는 ${animal.kind} 입니다. \n이 동물을 추가하시겠습니까?',
style: TextStyle(fontSize: 30.0),
),
actions: [
ElevatedButton(
onPressed: () {
widget.list?.add(animal);
Navigator.of(context).pop();
},
child: Text('예')),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('아니요'))
],
);
showDialog(
context: context,
builder: (BuildContext context) => dialog);
},
child: Text('동물 추가하기'))
],
...
_radioChange(int? value) { ... }
getKind(int? radioValue) {
switch (radioValue) {
case 0:
return "양서류";
case 1:
return "파충류";
case 2:
return "포유류";
}
}
AlertDialog의 Title은 알림 창에 표시할 제목이고, content는 내용이다.
actions는 배열 형태로 위젯을 가져올 수 있다. 여기서는 버튼을 두 개 선언해 각각 "예", "아니오" 를 Text로 보이도록 하였고, "예"를 누르면 리스트에 추가하고 꺼지도록, "아니오"를 누르면 그냥 꺼지도록 하였다.


