ref : 코딩 애플[Flutter로 만드는 iOS, Android 앱] 강의
부모에 total 이라는 state 를 만들어보자
total == 앱에 저장된 친구수
이 total 값은 appBar 에도 확인할 수 있게 해놓았다.
그리고 다이얼로그안에 있는 완료버튼을 눌렀을 때 저 값이 +1씩 되도록 만들어보려고한다.
저 다이얼로그가 새로운 친구 등록 화면임
부모위젯에 있는 state 인 total을 자식위젯에서 변경하고 싶으면
1. 일단 부모에 수정함수를 작성
addOne이라는 수정함수를 부모위젯에 작성했다.
state 를 수정하려면 setState에 넣어야했었다.
2. 자식위젯으로 보내기
왼쪽에는 작명
오른쪽에는 실제로 보내고 싶은 변수명(함수명)을 쓰면된다.
3. 그리고 자식위젯에 등록을 한다.
4. 실제로 사용한다.
완료 버튼이 onPressed 일 때 함수가 실행되도록 짰다.
아래처럼 잘 실행되는 것을 볼 수 있다.
input 데이터 다루기(유저가 입력한 데이터 다루기)
사용자가 입력한 데이터를 변수같은거에 저장하고 싶다면 controller: 라는 문법을 써야함
var inputData = TextEditingController();
다이얼로그 자식위젯 안에다가 inputData 라는 변수를 만들어줬다.
이 때 TextEditingController() 을 썼다.
TextField( controller: inputData,),
그 다음에 TextField 안에다가 controller 뒤에 변수이름을 써주면 저 변수에 데이터가 저장된다.
controller 보다 직관적인 방법이 있는데
onChanged : () {} 라는 방법이다.
onPressed 와 유사하게, 입력한 값이 변하게 되면 코드를 실행해달라는 의미
text 는 사용자가 입력한 값이고
입력한 값이 inputData2 라는 변수에 저장되게 될거다.
TextField가 많을 경우엔 어떻게 해야할까?
변수를 여러개 만들게 아니라
[ ] List
{ } Map
같은 거 활용하자
실습과제
다이얼로그에 TextField에다가 이름 입력하고 완료 누르면
4번째 친구로써 추가가 되어야한다.
name 이라는 리스트 state 에 새로운 친구의 이름을 추가하면 재렌더링이 될 것같다.
입력받은 변수를 addOne 함수와 써먹으면 될 것같다.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home : MyApp()
)
);
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var total = 3;
var like = [0,0,0];
var name = ['해리', '론', '헤르미온느'];
addOne(inputData){
setState(() {
name.add(inputData.toString());
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: (){
showDialog(context: context, builder: (context){
return DialogUI( addOne : addOne);
});
},
),
appBar: AppBar(title: Text(total.toString()),),
bottomNavigationBar: BottomAppBar(),
body: ListView.builder(
itemCount: name.length,
itemBuilder: (c, i){
return ListTile(
leading: Icon(Icons.account_box),
title: Text(name[i])
);
},
)
);
}
}
class DialogUI extends StatelessWidget {
DialogUI({Key? key, this.addOne}) : super(key: key);
final addOne;
var inputData = TextEditingController();
@override
Widget build(BuildContext context) {
return Dialog(
child: SizedBox(
width: 300,
height: 300,
child: Column(
children: [
TextField( controller: inputData,),
TextButton( child: Text('완료'),
onPressed: (){ addOne(inputData); },),
TextButton( child: Text('취소'),
onPressed: (){ Navigator.pop(context);},),
],
),
)
);
}
}
일단 addOne 함수에 inputData 를 받으면 name 이라는 리스트 state 에 inputData 를 추가하도록 해봤고
ListView.builder안에서 itemCount 는 3에서 name.length 로 수정해줬다.
뭔가 이상하다
추가는 되는데 추가되는 내용이 이상하다.
뭐가문제지
보니까 addName에 들어가는 inputData의 타입을 .toString() 으로 해주지않고
.text 로 해주었더니 잘 들어가진다.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home : MyApp()
)
);
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var total = 3;
var like = [0,0,0];
var name = ['해리', '론', '헤르미온느'];
addName(a){
setState(() {
name.add(a);
});
}
addOne(){
setState(() {
total ++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: (){
showDialog(context: context, builder: (context){
return DialogUI( addOne : addOne, addName : addName );
});
},
),
appBar: AppBar(title: Text('저는 친구가 ${name.length} 명 입니다.'),),
bottomNavigationBar: BottomAppBar(),
body: ListView.builder(
itemCount: name.length,
itemBuilder: (c, i){
return ListTile(
leading: Icon(Icons.account_box),
title: Text(name[i].toString())
);
},
)
);
}
}
class DialogUI extends StatelessWidget {
DialogUI({Key? key, this.addOne, this.addName}) : super(key: key);
final addOne;
final addName;
var inputData = TextEditingController();
@override
Widget build(BuildContext context) {
return Dialog(
child: SizedBox(
width: 300,
height: 300,
child: Column(
children: [
TextField( controller: inputData,),
TextButton( child: Text('완료'),
onPressed: (){
addOne();
addName(inputData.text);
Navigator.pop(context);
},),
TextButton( child: Text('취소'),
onPressed: (){ Navigator.pop(context);},),
],
),
)
);
}
}
완료버튼을 눌렀을때 추가로 창이 닫히게도 구현해봤는데
+ 추가로...
빈칸이면 완료눌러도 추가가 안되도록 하는 기능을 추가해봐야겠다.
+ 그리고 이름 옆에 삭제 버튼
+ 이름순 정렬버튼
+ 폰 번호 추가
등등 스스로 시도해보자..!
일단 빈칸일때에 완료누르면 추가가 안되도록 하는 기능은 조건문 사용해서 만들었다.
addName(a){
if (a == ''){
return;
}
else{
setState(() {
name.add(a);
});
}
완료버튼을 눌렀을 때에
나중엔 '이름을 입력해주세요!' 같은 안내가 나오면 더 좋을 것 같다.
버튼위에 + 모양을 넣어보았다.
child 안에 Text 를 넣고 style 중에 TextStyle 을 찾아 fontSize 를 30정도로 주었다.
그리고 삭제기능도 구현해보고 싶어서 delete 버튼을 만들어봤다.
기존에 있던 ListTile에서 trailing 을 써봤더니 내가 원하는 대로 각 라인의 맨 뒤에 자리 잡았다.
TextButton 으로 만들어 주었다.
그리고 TextButton 의 onPressed 안에 delete 함수를 넣어서 i번째 인덱스의 이름은 삭제되도록 했다.
delete 함수는 위에서 따로 만들었다.
delete 버튼 눌러봤는데 잘 지워지고 앱바에 있는 사람 수도 잘 줄어든다.