Search
▪️

Working with User Input & Forms

Scaffold.of(context).showSnackBar(SnackBar()))
showDialog(context :, builder: (context) {Dialog() or AlertDialog()})
showDialog 역시 일종의 Navigator기 때문에 Future 타입으로 값을 return 하게 된다.
Dismissible의 confirmDismiss는 Future 타입으로 bool 데이터를 통해 Dismiss여부를 결정하게 된다.
따라서 Navigator.of(context).pop()을 통해 값을 밀어 넣으면 Dismissible이 Dismiss에 대한 여부를 쉽게 판단할 수 있다.
TextField() Widget이 있음에도 Form() Widget을 쓰는 이유라 함은 Controller를 Manual하게 조정 해야할 뿐더러 Constraints에 대해서 일일이 검사를 해줘야 하기 때문에 쓴다.
일반적으로 child로 ListView or SingleChildScrollView과 같은 Scrollable한 속성의 Widget을 준다.
만일 Landscape Mode를 지원하고 싶다면 ListView 대신 SingleChildScrollView와 그 자식 Widget으로 Column을 주는 것이 좋다. Landscape Mode 이외에도 SingleChildScrollView와 Column으로 가두는 이유는 Soft Keyboard와 같이 갑작스런 화면 사이즈 조정, 혹은 굉장히 긴 input form에 대처하기 위한 것이다. 이와 같은 상황이 아니라면 Column으로 감싸지 않고 ListView를 써도 무방하다.
Form() Widget의 textInputAction으로 next를 주었을 때, 키보드에서 완료 버튼으로 다음 항목으로 넘기고 싶다면 focus node를 생성해서 manual하게 설정해야 한다.
1.
FocusNode 클래스를 담은 변수를 build 밖에 생성한다.
2.
첫 번째를 제외한 TextInputField의 focusNode 인자로 생성한 변수를 할당한다.
3.
넘겨주는 첫 번째 TextInputField에서 부터 onFieldSubmitted인자로 들어가는 함수에 FocusScope.of(context).requestFocus(해당 변수)로 요청한다.
4.
해당 FocusNode()들은 Memory Leak를 유발할 수 있다.
State들이 Screen을 옮김으로써 removed 되면 이 FocusNode들을 dispose해줘야 한다.
따라서 dispose() 함수를 override하여 해당 FocusNode들을 지워야 한다.
원래 Form() Widget을 쓰면 Editing Controller를 manual하게 설정할 필요는 없지만 이미지 preview처럼 뭔가를 미리 보여주고 싶다면 controller를 수동으로 추가할 필요가 있다. controller 역시도 dispose() Lifecycle에 추가해서 삭제할 필요가 있다.
TextFormField를 Row에 가둘 때는 조심해야 한다. 기본적으로 최대한 많은 width를 먹으려고 한다. 하지만 row에는 그런 constraints가 없다 보니 문제가 발생할 수 있다는 것이다. (unconstrained이고 child인 textformfield는 infinity로 먹으려고 한다. 이 와중에 또 다른 child인 container의 width를 모르는 상태이다.) 따라서 TextFormField를 Container로 가두는 것이 좋다.
imageUrl과 같이 입력이 끝났을 때, 해당 UI를 업데이트 하면서 preview를 보이고 싶다면 focusNode가 필요하다. 추가로 단순히 focusNode만 있으면 되는 것이 아닌, focusNode에 Listener를 달아야 한다. Listener 추가는 initState()의 Lifecycle에서 작성한다. Listener를 추가하는 이유는 해당 Node에 focus가 되어 있는지 아닌지 파악하기 위해서이다. 이렇게 Listener를 추가한 것도 반드시 dispose() Lifecycle에 삭제해야 한다. (<FocusNode>.hasFocus를 통해 Focus중인지 확인 가능하다.)
작성된 정보들을 Form의 onFieldSubmitted()함수를 통해 Save 할 수 있다. 이 때 요구되는 것이 global Key가 요구된다. GlobalKey<FormState>();로 Key를 생성하고, 이 GlobalKey 덕에 Form Widget 뒤에 있는 State들과 interact할 수 있게 된다. key를 Form Widget에 등록하고 나면 save뿐만 아니라 autovalidate 기능도 쓸 수 있게 된다.
Validating도 마찬가지로 Form Widget에서 가능하다. TextFormField의 validator인자를 통해서 검증한다. validator는 function이며 null return시 error free라는 것을 의미한다.Form Widget에서 autovalidate를 true로 할 시 모든 TextFormField에 대한 validation을 수행한다.만일 일일이 검증은 하기 싫으면서 모든 Field의 검증은 하고 싶다면 autovalidate를 false로 두고 <globalKey>.currentState.validate()를 통해서 검증하면 됨
Form Widget에서 Controller가 있는 TextFormField Widget 내에는 initialValue를 지정할 수 가 없다.따라서 controller.text의 값을 직접 조정해야 한다.
Form Widget은 onFieldSubmitted()함수 호출 후에 onSaved()함수를 호출한다.
double.tryParse는 double.parse를 하여 결과를 내놓는 것과 달리 double로 parsing이 가능한지에 대한 여부를 확인하는 것이 가능하다. return이 null이면 불가능하다는 의미이다.
dart는 내장 함수로 (value).startsWith('pattern')와 (value).endsWith('pattern')을 지원한다. 따라서 간단한 checking에는 이런 함수들을 이용하면 되고, 좀더 복잡한 검증에 한에서만 Regular Expression을 통해서 확인하도록 한다. 매 확인 마다 Regular Expression을 쓰는 것은 좋지 않다.
r로 시작하는 regular expression class를 dart에서 제공한다.
<List>.insert(index, item)을 통해서 index위치에 삽입도 가능하다.
<List>.indexWhere()을 통해서 조건에 맞는 index을 찾을 수 있다.