파파비의 블로그

플러터, flutter) Input을 도와주는, Form 위젯(1) - Form 기본 및 설정 본문

개발/flutter

플러터, flutter) Input을 도와주는, Form 위젯(1) - Form 기본 및 설정

N. Dave 2020. 6. 9. 21:40
반응형

입력을 받는 방법이 여러가지가 있다만, TextField를 다룬 적이 있다.

이것은 controller도 직접 달아야하고,

또 값을 매번 변할 때마다 어딘가에 저장도 따로 해주어야 하며,

특히 input에서 유효한값인지 아닌지도 판별할 때 직접 코딩으로 처리했어야했다.

 

이런 불편한 작업들을 덜어주는게 있는데,

그래서 더 정교한(?) input 컨트롤을 가능하게 해주는 위젯이 있다.

 

바로 "Form" 위젯이다.

Form위젯은 먼저 형태가 없다. 그냥 컨트롤을 도와주는 위젯이다.

따라서 자식으로 input 관련 위젯을 넣어야 한다.

아래 코드를 살펴보자

 

간단한 형태다. 여기서 TextFormField는 자동으로 Form위젯과 연결된다.

데코레이션에서 labelText의 역할은 Hint비스무리한 역할로, 입력이 없을땐 hint쪽에 위치하고, 입력이 시작되면 위로 옮겨진다.

 

textInputAction은 소프트키보드의 우측 하단의 버튼을 결정한다. 

여기서는 Next로 되어있는데,

 

그래서 저런 초록색 버튼 모양이다.

참고로 Title(labelText)의 사이즈도 살펴보면 좋다

 

textInputAction: TextInputAction.next 으로 설정할 경우 모양이 바뀐 것을 확인할 수 있다!

 

 

<참고>

보통 폼안에 차일드로 colunm을 넣고 여러 개의 inputfield를 넣게 되는데, 

만약 Listview를 쓰거나 그러면 inputfield가 여러개 일 경우 버그가 생길 수 있다.

왜냐하면 Listview는 스크롤을 일정 이상하면 오브젝트가 지워져서 거기에 담긴 내용들도 사라지기 때문이다.

 

따라서 스크롤을 많이 해야하는 경우에는 

Colunm + SingleScrollView 조합으로 하면 된다. 얘네들은 그렇게 사라지는 경우가 없기 때문이다.

 

https://www.udemy.com/course/learn-flutter-dart-to-build-ios-android-apps/learn/lecture/15145432#questions

 

 

Next 버튼눌러서 다른 Input으로 이동시키기

지금은 우측하단의 버튼을 눌러도 아무런 반응이 없다. 왜냐면 설정해 둔 것이 없기 때문이다.

우리는 next버튼을 누르면 다음 어디로 'focus'가 되도록 설정할 것인지 미리 설정을 해놔야 한다.

 

우리는 next버튼을 눌렀을 때, 다른 TextFormField로 Focus를 집중시키기 위해선, 

 

TextFormField의 FocusNode를 지목해야 한다.

1) 따라서 지목 당하는 TextFormField는 FocusNode를 가지고 있어야하며,

2) 우리는 우측하단의 버튼을 누르는 순간 callback으로 그 명령을 실행해야 한다.

 

 

일단 폼안에 3개의 TextFormField를 넣어두었다.

그리고 2번째 TextFormFielddpsms focusNode가 _priceFocusNode이고, 3번째의 focusNode는 _testFocusNode이다.

 

 

이미 이렇게 FocusNode의 객체로 미리 만들어놓고 배정해 두었다.

첫번째는 시작점이기 때문에 FocusNode를 따로 설정하지않았다.

 

 

다음은 onFieldSubmitted 콜백인데, 여기서 우리는 focus를 다음 focusNode로 넘기는 작업을 한다.

이 함수는 우측하단의 버튼이 눌려지면 실행이 된다. 그 버튼이 어떤 모양인지는 중요하지 않다. 그냥 그 버튼이 눌리면 실행이 된다.

 

우리는 거기에 콜백으로 

FocusScope 객체를 통해 Focus를 _priceFocusNode를 가진 객체로 옮겨달라고 요청하고 있는 것이다.

이 원리로 우리는 Next 버튼을 실현한다.

 

 

FocusNode들은 항상 Dispose처리를 따로 해주어야한다.

얘네들은 state가 사라질때도 남아있는다, 따라 반드시 따로 없애는 처리를 해주어야한다.

그래서 form 위젯이 들어가는 위젯은 Stateful이어야 한다.

이렇게 dispose() 콜백을 넣어서 state이 사라질 때, 반드시 같이 사라지도록 해주어야 한다.

 

 

 

 

<참고>

이 코드를 보면 키보드 타입을 멀티라인으로 했다.

키보드 타입을 어떻게 설정하느냐에 따라 

우측하단 버튼의 설정인, TextInputAction이랑 명령이 겹쳐질 수 있다.

multiline 키보드 타입은 우측하단의 버튼이 줄바꿈으로 되기 때문이다.

이렇게 기능이 겹칠 경우 한 가지는 무시된다.

따라서 여기서는 위의 경우처럼 다음 input으로 넘어가게 하거나 or 줄바꿈으로 하거나 둘중 하나만 선택할 수 있다.

 

또한 여기는 Maxlines 이 3인데, 그래서 애초부터 3줄이 보여진다. 한줄에서 길이에 따라 3줄로 늘어나는 구조가 아니다.

 

Form은 제출완료시 값을 컨트롤 한다. 그전에 값을 받아보고 싶으면 Controller를 사용하면 된다.

1) Controller 위젯은 TextEditingController 라는 위젯이다.

 - 이 위젯을 미리 초기화 하고, 레퍼런스를 넘기도록 한다. (그래야 나중에 레퍼런스를 통해 객체에 접근이 가능하다)

 - 이 컨트롤러는 값이 입력되는 즉시 해당 값을 가져올 수 있다.

 

2) TextEditingController 역시 dispose처리를 반드시 따로 해주어야 한다.

이렇게 말이다.

 

 

URL을 입력하고 미리보기를 실현해보자

URL을 텍스트로 입력 받고 그 값을 받는 즉시 Image로 만들어

서 가져와보자.

화면은 이렇게 생겼다.

 

코드 구조는 이렇다. Row 안에 컨테이너와 Expanded가 있고, 그 안에 각각 Image와 TextFormField가 있다.

 

point 1) TextFormField처럼 text를 입력받는 것들은 가로로 무한히 간다.

따라서 부모가 사이즈가 고정되어 있지 않다면 에러가 뜬다.

여기서 row는 가로로 무한히 커지므로, row안에 바로 TextForm을 넣으면 에러가 뜨게 된다.

따라서 Expanded로 나머지 공간을 정확히 계산해서 고정값으로 만들면 해결이 된다.

 

point 2) 완료버튼 클릭시 setState을 통해 입력값이 존재하면 그 값을 인터넷으로 연결, 이미지를 가져오도록 한다

 

 

그런데, 꼭 완료 버튼을 눌러야 할까?

그러지말고, 그냥 입력이 취소되어도 가져오게 하고 싶다.

입력이 취소되었을 때의 리스너는 따로 없어서 우리가 설정해주어야 한다.

 

방법은 간단하다.

FocusNode를 활용하는 것이다.

 

FocusNode에는 리스너가 있다.

FocusNode를 가진 위젯이 선택되거나 선택이 풀릴 때, 콜백메서드를 실행시킬 수 있다.

 

 

point 1) FocusNode객체를 만들었고, 그것을 TextFormField 객체에 설정했다(설정한 것은 위에 코드 이미지를 참고)

 

point 2) initstate로, 앱이 실행될 때, 리스너에 콜백메소드를 달았다.

 - 그 메소드는 포커스가 풀릴 때 마다 setstate를 실행시키는 것이고, setstate이 실행되면 build시 입력값이 있으면 url에서 이미지를 가져오도록 하는 그 방법에 따라 이미지를 가져오게 된다. 

 

point 3) FocusNode 자체와, 리스너를 각각 dispose해준다. 

 

 

 

 

반응형
Comments