일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Three-fiber
- code editor
- FirebaseAnalytics
- Flutter
- uint16array
- userevent_tracker
- Game js
- Image Resize typescript
- Babel standalone
- node
- KakaoMap
- Raycasting
- jszip
- Completer
- webrtc
- RouteObserver
- swagger-typescript-api
- Excel
- REST API
- Prism.js
- uint8array
- babel
- androidId
- react
- methodChannel
- Redux
- typescript
- identifierForVender
- Three js
- web track
- Today
- Total
Never give up
Flutter - When to use Enum(feat. authentication) 본문
필자가 생각하는 Enum의 사용처는 리펙토링할 때 직관적이게 하는것인거 같습니다
(ex : 하드코딩으로 넘기는 int값이 꼴뵈기 싫을때..?)
bool으로 간단히 처리할 수 있는것은 bool을 사용하는게 좋지만
예를들어 3개 이상일 때는 어떨까요?
앞에 ex 부분에 장난식으로 써놓긴 했지만 실제로 index값에 따른 동작을
한번 더 확인해야되는 불편함이 있고 직관적이지 않습니다
그래서 회원가입 예제를 통해 알아보겠습니다
Main
enum AuthState { Correct, InvalidID, ShortLength, Different }
enum AuthText { ID, Password, Check }
class EnumExample extends StatelessWidget {
final AuthData _data = AuthData();
final _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
var scope = FocusScope.of(context);
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(title: Text('Enum example')),
body: InkWell(
onTap: () {
if (scope.hasFocus) {
scope.unfocus();
}
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Create new account',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
shadows: [
Shadow(color: Colors.grey[400], offset: Offset(2, 2))
]),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
child: ListView.separated(
shrinkWrap: true,
itemCount: 3,
itemBuilder: (context, index) {
AuthText text = AuthText.values[index];
return ListTile(
leading: _getIcon(index),
title: TextFieldWidget(data: _data, text: text));
},
separatorBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 40),
child: Divider(thickness: 2),
);
},
),
),
),
ButtonTheme(
height: 40,
minWidth: double.infinity,
child: RaisedButton(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
child: Text('Register',
style: TextStyle(color: Colors.white, fontSize: 16)),
color: Colors.blue,
onPressed: () {
switch (_data.getState) {
case AuthState.Correct:
break;
case AuthState.InvalidID:
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
'Email address is invalid. Please use right email address.')));
return;
case AuthState.Different:
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
'Password is incorrect. Please try again.')));
return;
case AuthState.ShortLength:
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(
'Password is too weak. It should be longer than 6.')));
return;
}
}),
)
],
),
),
),
);
}
Icon _getIcon(int index) {
switch (index) {
case 0:
return Icon(Icons.email_outlined);
case 1:
return Icon(Icons.lock);
case 2:
return Icon(Icons.fact_check_outlined);
default:
return Icon(Icons.device_unknown);
}
}
}
TextField widget
class TextFieldWidget extends StatefulWidget {
final AuthData data;
final AuthText text;
TextFieldWidget({@required this.data, @required this.text});
@override
_TextFieldWidgetState createState() => _TextFieldWidgetState();
}
class _TextFieldWidgetState extends State<TextFieldWidget> {
TextEditingController _controller = TextEditingController();
bool _isPassword = true;
@override
void initState() {
super.initState();
if (widget.text == AuthText.ID) {
_isPassword = false;
}
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextFormField(
controller: _controller,
keyboardType: _isPassword
? TextInputType.visiblePassword
: TextInputType.emailAddress,
decoration: InputDecoration(
border: InputBorder.none,
hintText: _isPassword
? ((widget.text == AuthText.Check)
? 'Check Password'
: 'Password')
: 'Email'),
obscureText: _isPassword,
onChanged: (value) {
switch (widget.text) {
case AuthText.ID:
widget.data.setId(value);
break;
case AuthText.Password:
widget.data.setPassword(value);
break;
case AuthText.Check:
widget.data.setCheck(value);
break;
}
},
);
}
}
Data
class AuthData {
String _id, _password, _check;
String get getId => _id;
get getPassword => _password;
void setId(String value) {
_id = value;
}
void setPassword(String value) {
_password = value;
}
void setCheck(String value) {
_check = value;
}
get isSame => (_password == _check);
AuthState get getState {
if (_password.length < 6) {
return AuthState.ShortLength;
} else if (!RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
.hasMatch(_id)) {
return AuthState.InvalidID;
}
if (isSame) {
return AuthState.Correct;
} else {
return AuthState.Different;
}
}
}
먼저 필자가 사용한 enum은 2가지로 Textfield의 구분동작을 위한 AuthText와
Register버튼을 눌렀을 때의 상태를 체크해주는 AuthState를 만들어봤습니다
Listtile안에 있는 Textfield부분에서 구분동작을 위해 index에 따른 AuthText값을 할당합니다
그러면 onChange가 발생할 때 switch문을 통해 필요한 곳에 값이 전달이 됩니다
값을 입력한 후에 register를 누르면 switch문에서 data class에서 설정한 getState값에 따라 출력이 바뀌게 됩니다
(email validation같은 경우 stackoverflow.com/questions/16800540/validate-email-address-in-dart에서 그대로 가져와서 사용했습니다)
다시한번 정리하자면 비교인자가 2개일 경우에는 bool을 사용하는게 좋고
3개 이상일 경우 enum을 사용하면 조금 더 직관적이다 정도로 마무리하면 될거 같습니다
(물론 int, string 등 다른 타입을 사용해도 무방합니다)
'Flutter' 카테고리의 다른 글
Flutter - CachedNetworkImageProvider error handling? (0) | 2020.12.29 |
---|---|
Flutter - When you store collection in cloud firestore (0) | 2020.12.23 |
Flutter - context, key example with snackbar, provider (0) | 2020.11.16 |
Flutter - Map<key, List<data>> with Listview(simple chatting screen) (0) | 2020.11.02 |
Flutter - Search item in List and how to keep TextField from keyboard (0) | 2020.10.05 |