플러터) flutter 2 - 이벤트 위젯
1. 사용자 입력 처리 위젯
1) 텍스트 필드
TextField(
style: TextStyle(fontSize: 15),
textAlign: TextAlign.center
)
(1) 입력된 데이터 얻기 - TextEditingController
- 텍스트 필드에 입력된 데이터 얻기
class TextState extends State<TestScreen> { final controller = TextEditingController(); // 데이터 획득, 변경 이벤트 감지 클래스 Widget build(BuildContext context){ return Column( children:[ TextField( style: TextStyle(fontSize: 15.0), controller: controller, // 컨트롤러 연결 ), ElevatedButton( child: Text('submit'), onPressed: () { print('submit : ' + controller.text); // 획든한 데이터 출력 }) ]); } }
- 텍스트 필드값 변경 감지 방법
@override void initState() { super.initState(); controller.addListener(_printValue); // 한 글자씩 입력될 때마다 (매개변수 함수) 처리 } @override void dispose() { super.dispose(); controller.dispose(); // 텍스트 감지 필요 없을 시 호출 }
(2) 꾸미기 - InputDecoration
- InputDecoration 속성
- labelText : 라벨 문자열
- helperText : 아래쪽에 출력되는 설명 문자열
- hintText : 입력 상자 안쪽에 출력되었다가 글 입력 시 사라지는 문자열
- errorText : 아래쪽에 출력되는 오류 문자열
- prefixIcon : 입력 앞 부분에 고정으로 출력되는 아이콘 이미지
- counterText : 아래쪽에 출력되는 문자열
- border : 테두리 지정(OutlineInputBoarder, UnderlineInputBoarder 중 하나 이용)
- 코드 예시
TextField( style : TextStyle(fontSize:15.0), controller : controller, decoration: InputDecoration( labelText: 'Name', prefixIcon: Icon(Icons.input), border: OutlineInputBorder(), hintText: "Hint Text", helperText: "이름을 입력하세요.", counterText: "$textCounter characters")) // errorText: "error text"
(3) 액션 버튼 - textInputAction
- textInputAction 속성
- TextInputAction.next : 다음 위젯으로 포커스 이동
- TextInputAction.previous : 이전 위젯으로 포커스 이동
- TextInputAction.search : 검색 버튼
- TextInputAction.send : 전송 버튼
- 코드 예시
TextField( textInputAction: TextInputAction.search )
(4) 키보드 유형 - keyboardType
- keyboardType 상수 설정
- TextInputType.number : 숫자 입력
- TextInputType.text : 문자 입력
- TextInputType.phone : 전화번호 입력
- TextInputType.emailAddress : 이메일 주소 입력
- TextInputType.url : URL 입력
- 코드 예시
TextField( keyboardType: TextInputType.number )
(5) 텍스트 감추기 - obscureText
- 예시 : ****
- 코드 예시
TextField( obscureText: true )
(6) 여러 줄 입력 - maxLines, minLines
- 기본 : 한 줄 입력
- 코드 예시
TextField( minLines: 2, maxLines: 5 )
✨코드 예시
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: TestScreen()));
}
}
class TestScreen extends StatefulWidget {
@override
TextState createState() => TextState();
}
class TextState extends State<TestScreen> {
final controller = TextEditingController();
int textCounter = 0;
_printValue() {
print("_printValue(): ${controller.text}");
setState(() {
textCounter = controller.text.length;
});
}
@override
void initState() {
super.initState();
controller.addListener(_printValue);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
print("build....");
return Column(
children: [
Text('TextField Test'),
TextField(
style: TextStyle(fontSize: 15.0),
controller: controller,
decoration: InputDecoration(
labelText: 'Data',
prefixIcon: Icon(Icons.input),
border: OutlineInputBorder(),
hintText: "Hint Text",
helperText: "데이터를 입력하세요.",
counterText: "$textCounter characters",
),
textInputAction: TextInputAction.search,
keyboardType: TextInputType.emailAddress,
minLines: 5,
maxLines: 5,
)],);}}
2) 체크박스, 라디오 버튼, 슬라이더, 스위치
(1) 체크박스 - Checkbox
- 체크박스 출력하기
Checkbox( value: isChecked, onChanged: (bool? value) { setState(() { isChecked = value; });})
(2) 라디오 버튼 - Radio
- groupValue : 그룹 간에 하나만 선택할 수 있음
Row( children: [ Radio( value: "android", groupValue: selectPlaform, // 한 묶음 onChanged: (String? value) { setState(() { selectPlatform = value; }); } ), Text('android') ]), Row( children: [ Radio( value: "ios", groupValue: selectPlaform, // 한 묶음 onChanged: (String? value) { setState(() { selectPlatform = value; }); } ), Text('ios') ]), Text('select platform is $selectPlatform')
(3) 슬라이더 - Slider
- 슬라이더 출력하기(min, max 속성으로 값 설정)
Slider( value: selectValue, min: 0, max: 10, onChanged: (double value) { setState(() { selectValue = value; });})
(4) 스위치 - Switch
- 스위치 출력하기
Switch( value: selectValue, onChanged: (bool value) { setState(() { selectValue = value; });})
✨코드 예시
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: TestScreen()));
}
}
class TestScreen extends StatefulWidget {
@override
TextState createState() => TextState();
}
class TextState extends State<TestScreen> {
bool? isChecked = true;
String? selectPlatform;
double sliderValue = 5.0;
bool switchValue = true;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Checkbox Test'),
Row(
children: [
Checkbox(
value: isChecked,
onChanged: (bool? value) {
setState(() {
isChecked = value;
});
}),
Text("checkbox value is $isChecked")
],
),
Text('Radio Test'),
Row(
children: [
Radio(
value: "android",
groupValue: selectPlatform,
onChanged: (String? value) {
setState(() {
selectPlatform = value;
});
}),
Text('android')
],
),
Row(
children: [
Radio(
value: "ios",
groupValue: selectPlatform,
onChanged: (String? value) {
setState(() {
selectPlatform = value;
});
},
),
Text('ios')
],
),
Text('select plaform is $selectPlatform'),
Text('Slider Test'),
Slider(
value: sliderValue,
min: 0,
max: 10,
onChanged: (double value) {
setState(() {
sliderValue = value;
});
}),
Text('slider value is $sliderValue'),
Text('Switch Test'),
Switch(
value: switchValue,
onChanged: (bool value) {
setState(() {
switchValue = value;
});
}),
Text('select value is $switchValue')
],);}}
3) 폼 이용하기
- 유효성 검증, 데이터 관리 등을 위해 이용 가능
(1) 폼에 키값 대입하기
- TextFormField에는 validator와 onSaved 속성에 함수를 설정할 수 있음(TextEditingController를 사용하지 않고 사용자 입력 데이터 받을 수 있음)
class MyFormState extends State { final _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Column(children: [Form(key: _formKey)]); } }
(2) 유효성 검증과 데이터 저장하기
- FormState가 제공하는 validate(), save() 함수 실행 시 validator, onSaved 속성에 설정한 함수 호출
Form( key: _formKey, child: Column(TextFormField( decoration: InputDecoration(labelText: 'FirstName'), validator: (value) { if (value?.isEmpty ?? flase) { return 'Please enter first name'; } return null; }, onSaved: (String? value) { firstName = value; }, ))), ElevatedButton( onPressed: () { if (_formKey.currentState?.validate() ?? false) { _formKey.currentState?.save(); print('firstName: $firstName, lastName : $lastName'); } }, child: Text('submit') )
✨코드 예시
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: TestScreen()));
}
}
class TestScreen extends StatefulWidget {
@override
MyFormState createState() => MyFormState();
}
class MyFormState extends State<TestScreen> {
final _formKey = GlobalKey<FormState>();
String? firstName;
String? lastName;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Form Test'),
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'FirstName'),
validator: (value) {
if (value?.isEmpty ?? false) {
return 'Please enter first name';
}
return null;
},
onSaved: (String? value) {
firstName = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'LastName'),
validator: (value) {
if (value?.isEmpty ?? false) {
return 'Please enter last name';
}
return null;
},
onSaved: (String? value) {
lastName = value;
}),
],
)),
ElevatedButton(
onPressed: () {
if (_formKey.currentState?.validate() ?? false) {
_formKey.currentState?.save();
print('firstName: $firstName, lastName : $lastName');
}
},
child: Text('submit'))
],);}}
2. 목록 구성과 다이얼로그 위젯
1) 리스트 뷰
(1) 스크롤이 필요한 상황
- 스크롤 지원 리스트 뷰
ListView( scrollDirection: Axis.horizontal // 위젯을 가로로 나열하기 children: [ Container(height: 300, color: Colors.red), Container(height: 300, color: Colors.green), Container(height: 300, color: Colors.blue) ])
(2) 목록 구성하기
- 항목을 스크롤에 따라 불러오기
List<String> citys = [ '서울시', '인천시', '부산시', '대구시', '대전시', '광주시', '울산시', '세종시' ] @override Widget build(BuildContext context) { return ListView.builder( itemCount: citys.length, itemBuilder: (context, index){ return Container( padding: EdgeInsets.only(left: 10, top: 10), height: 100, child: Text(citys[index]) );},);}
- 항목 구분자 설정하기
ListView.separated( itemCount: citys.length, itemBuilder: (context, index) { return Container( padding: EdgeInsets.only(left: 10, top: 10), height: 100, child: Text(citys[index]), ) } separatorBuilder: (context, index) { return Divider(height: 2, color: Colors.black); } )
(2) 항목 구성하기 - ListTile
- 항목 구성하기
ListView.separated( itemCount: users.lengtth, itemBuilder: (context, index) { return ListTile( leading: CircleAvatar( radius: 25, backgroundImage: AssetImage('images/big.jpg'), ), title: Text(users[index].name), subtitle: Text(users[index].phone), trailing: Icon(Icons.move_vert), onTap: () { print(users[index].name); } )}, separatorbuilder: (context, index) { return Divider(height: 2, color: Colors.black); },)
✨코드 예시
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class User {
String name;
String phone;
String email;
User(this.name, this.phone, this.email);
}
class MyApp extends StatelessWidget {
List<User> users = [
User('홍길동', '0100001', 'a@a.com'),
User('김길동', '0100002', 'b@a.com'),
User('이길동', '0100003', 'c@a.com'),
User('박길동', '0100004', 'd@a.com'),
User('홍길동', '0100001', 'a@a.com'),
User('김길동', '0100002', 'b@a.com'),
User('이길동', '0100003', 'c@a.com'),
User('박길동', '0100004', 'd@a.com')
];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: ListView.separated(
itemCount: users.length,
itembuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
radius: 25,
backgroundImage: AssetImage('images/big.jpg'),
),
title: Text(users[index].name),
subtitle: Text(users[index].phone),
trailing: Icon(Icon.more_vert),
onTap: () {
print(users[index].name);
});
},
separatorBuilder: (context, index) {
return Divider(height: 2, color: Colors.black);
},
)));}}
2) 그리드 뷰
- 항목을 세로로 배치하기
GridView.builder( itemCount: citys.length, itemBuilder: (context, index) { return Card( child: Text(citys[index]), );}, gridDelegate: SliverGridDelegateWithfixedCrossaxisCount(crossAxisCount: 2), )
- 항목을 가로로 배치하기
GridView.builder( scrollDirection: Axis.horizontal, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), )
✨코드 예시
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
List<String> citys = ['서울시', '인천시', '부산시', '대구시', '대전시', '광주시', '울산시', '세종시'];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: GridView.builder(
itemCount: citys.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Text(citys[index]),
Image.asset('images/big.jpg')
],
),
);
},
scrollDirection: Axis.horizontal,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
)));
}
}
3) 페이지 뷰
✨ 코드 예시
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
PageController controller =
PageController(initialPage: 1, viewportFraction: 0.8);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: PageView(
controller: controller,
children: [
Container(
margin: EdgeInsets.all(20),
color: Colors.red,
child: Center(
child: Text('OnePage',
style: TextStyle(color: Colors.white, fontSize: 30)),
),
),
Container(
margin: EdgeInsets.all(20),
color: Colors.green,
child: Center(
child: Text('TwoPage',
style: TextStyle(color: Colors.white, fontSize: 30)),
),
),
Container(
margin: EdgeInsets.all(20),
color: Colors.blue,
child: Center(
child: Text('ThreePage',
style: TextStyle(color: Colors.white, fontSize: 30)),
),
)
],
)));
}
}
4) 다이얼 로그 띄우기
(1) 알림 창 - AlertDialog
- 기본 알림 창 띄우기
showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text("Dialog Title"), content: Text("Dialog Message"), action: [ TextButton( onPressed: () { Navigator.of(context).pop(); }, child: Text("OK") ) ], );});
- 사용자 입력을 받는 알림 띄우기
AlertDialog( title: Text("Dialog Title"), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( decoration: InputDecoration(borer: OutlineInputBorder()), ), Row( children: [ Checkbox(value: true, onChanged: (value) {}), Text('수신동의') ], ) ], ), actions: [ TextButton( onPressed: (){ Navigator.of(context).pop(); }, child: Text("OK") ) ] )
(2) 보텀 시트 - BottomSheet
- showBottomSheet() : 검은 화면 아님
- showModalBottomSheet() : 검은 화면 됨(모달)
- 보텀 시트 띄우기
showModalBottomsheet( context: context, backgroundcolor: Color.yellow, builder: (context) { return SafeArea( child: Column( mainAxisSize: MainAxissize.min, children: [ ListTile( leading: Icon(Icons.add), title: Text('ADD'), onTap: () { Navigator.of(context).pop(); }, ), ListTile( leading: Icon(Icons.remove), title: Text('REMOVE'), onTap: () { Navigator.of(context).pop(); },)]))})
(3) 날짜, 시간 선택 창 - DatePickerDialog, TimePickerDialog
- 날짜 선택 창(DatePickerDialog)
DateTime? picked = await showDatePicker( context: context, initialDate: new DateTime.now(), firstDate: new DateTime(2016), lastDate: new DateTime(2030); )
- 시간 선택 창
TimeOfDay? selectedTime = awaitshowTimePicker( initialtime: TimeOfDay.now() context: context, )
✨ 코드 예시
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: TestScreen()));
}
}
class TestScreen extends StatefulWidget {
@override
TextState createState() => TextState();
}
class TextState extends State<TestScreen> {
DateTime dateValue = DateTime.now();
TimeOfDay timeValue = TimeOfDay.now();
_dialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Dialog Title"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: InputDecoration(border: OutlineInputBorder()),
),
Row(
children: [
Checkbox(value: true, onChanged: (value) {}),
Text('수신동의')
],)
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("OK"))
],
);
});
}
_bottomSheet() {
showBottomSheet(
context: context,
backgroundColor: Colors.yellow,
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(Icons.add),
title: Text('ADD'),
onTap: () {
Navigator.of(context).pop();
},
),
ListTile(
leading: Icon(Icons.remove),
title: Text('REMOVE'),
onTap: () {
Navigator.of(context).pop();
}
)
],
);
});
}
_modalBottomSheet() {
showModalBottomSheet(
context: context,
backgroundColor: Colors.yellow,
builder: (context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(Icons.add),
title: Text('ADD'),
onTap: () {
Navigator.of(context).pop();
},
),
ListTile(
leading: Icon(Icons.remove),
title: Text('REMOVE'),
onTap: () {
Navigator.of(context).pop();
},
)
],
)
);
});
}
Future datePicker() async {
DateTime? picked = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime(2016),
lastDate: new DateTime(2030));
if (picked != null) setState(() => dateValue = picked);
}
Future timePicker() async {
TimeOfDay? selectedTime = await showTimePicker(
initialTime: TimeOfDay.now(),
context: context,
);
if (selectedTime != null) setState(() => timeValue = selectedTime);
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(onPressed: _dialog, child: Text('dialog')),
ElevatedButton(onPressed: _bottomSheet, child: Text('bottomsheet')),
ElevatedButton(
onPressed: _modalBottomSheet, child: Text('modal bottomsheet')),
ElevatedButton(onPressed: datePicker, child: Text('datepicker')),
Text('date : ${DateFormat('yyyy-MM-dd').format(dateValue)}'),
ElevatedButton(onPressed: timePicker, child: Text('timepicker')),
Text('time : ${timeValue.hour}:${timeValue.minute}'),
],
)
);
}
}
5) 탭바 뷰
- 탭 화면을 구성하는 위젯
controller = TabController(length: 3, vsync: this); TabBar( controller: controller, tabs: <Widget>[ Tab(text: 'One'), Tab(text: 'Two'), Tab(text: 'Three') ] )
✨ 코드 예시
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<MyApp>
with SingleTickerProviderStateMixin {
late TabController controller;
@override
void initState() {
super.initState();
controller = TabController(length: 3, vsync: this);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Tab Test'),
bottom: TabBar(controller: controller, tabs: <Widget>[
Tab(text: 'One'),
Tab(text: 'Two'),
Tab(text: 'Three'),
])),
body: TabBarView(
controller: controller,
children: <Widget>[
Center(
child: Text(
'One Screen',
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
),
Center(
child: Text(
'Two Screen',
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
),
Center(
child: Text(
'Three Screen',
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
)
],
)));
}
}
댓글남기기