2. 로그인 화면 필수 요소들 - 인풋필드 만들기 ( Controller,FocusNode,initState,dispose )
시작전 요약
TextEditingController()
역할: 사용자가 입력한 데이터를 저장하고 관리하는 역할을 합니다.
FocusNode()
역할: 특정 입력 필드에 포커스를 제어하는 역할을 합니다. 즉, 현재 어떤 입력 필드가 활성화되어 있는지를 나타냅니다.
initState()
이유: 위젯이 처음 만들어질 때 한 번만 호출됩니다. 이곳에서 초기 설정을 하거나 리스너를 추가해야 합니다.
예시: 입력 필드에 포커스가 생겼을 때 반응하려면, 이곳에서 리스너를 추가해야 합니다.
dispose()
이유: 위젯이 더 이상 필요하지 않을 때 호출됩니다. 이곳에서 리스너를 제거하고 리소스를 정리합니다.
예시: 포커스 리스너를 제거하여 메모리 누수를 방지하고, 기본 상태로 돌아가게 합니다.
컨트롤러
이번에 만들 것은
이런 인풋필드입니다.
기초 컨트롤러에 대해서 설명하겠습니다.
final _textController = TextEditingController();
먼저 우리가 이메일에 텍스트를 적는데 그걸 저장시킬 친구가 필요한데
그 친구가 TextEditingController() 이 친구입니다. 우리는 이 친구를 _textController라고 부르기로 했어요. (변수)
TextEditingController는 클래스이며, TextEditingController()는 그 클래스의 인스턴스를 생성하는 생성자입니다.
이제 컨트롤러를 넣을 ui가 필요하겠죠?
TextField, TextFormField 이런 것들이 있는데
저는 커스텀이 가능한 TextFormField이 친구를 쓸 거예요
TextFormField 안에 저희가 아까 만든 변수를 넣어줍니다. 이렇게 되면
이 인풋필드 안에 우리가 적은 텍스트들이 바운딩되겠죠?
controller: _textController,
포커스
근데 우리가 사용자가 눌렀을 때 인풋필드가 변하게 만들고 싶잖아요?
예를 들어
이렇게 빨간색으로 변하거나 파란색으로 사용자가 오류가 났을 때, 사용자가 눌렀을 때 확인을 시켜줘야 되는데
그걸 만들기 위해서 포커스가 중요합니다.
final FocusNode _emailfocusNode = FocusNode();
이런 식으로 이메일 포커스를 만들어줄게요.
FocusNode
역할: 특정 입력 필드에 포커스를 제어하는 역할을 합니다. 즉, 현재 어떤 입력 필드가 활성화되어 있는지를 나타냅니다
TextFormField(
controller: _textController,
focusNode: _emailfocusNode,
),
이런식으로 이제 포커스와 컨트롤러가 들어가게 된다면 준비는 끝났습니다.
이제 자기가 원하는 텍스트 스타일과
style: TextStyle(
color: Color(0xFF3D3D3D),
fontSize: 16,
fontFamily: 'Pretendard',
fontWeight: FontWeight.w500,
height: 1.0,
letterSpacing: -0.4,
),
데코레이션을 넣어주고
InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
contentPadding: EdgeInsets.only(bottom: 10),
hintText: '이메일입니다.',
hintStyle: TextStyle(
color: Color(0xFF888888),
fontSize: 16,
fontFamily: 'Pretendard',
fontWeight: FontWeight.w500,
height: 1.0,
letterSpacing: -0.4,
),
suffixIcon: _textController.text.isNotEmpty
? IconButton(
onPressed: () {
_textController.clear();
setState(() {});
},
padding:
EdgeInsets.only(bottom: 10, left: 60),
icon: Icon(Icons.cancel,
color: Color(0xFF888888)))
: null),
이 부분은
suffixIcon: _textController.text.isNotEmpty
? IconButton(
onPressed: () {
_textController.clear();
setState(() {});
},
padding:
EdgeInsets.only(bottom: 10, left: 60),
icon: Icon(Icons.cancel,
color: Color(0xFF888888)))
텍스트가 입력 됐을 때 X아이콘을 눌렀을 때 컨트롤러를 다 지워주는 역할을 하는데
크게 안 넣어도 됩니다.
Color _emailborderColor = Color(0xFFD1D1D1); // 기본 테두리 색상
이제 컬러 색을 바꾸기 위해서 원래있던 기본 테두리 색상을 정의해두고 변수하나를 만들어줍니다.
저는 테두리 부분 색을 바꾸고 싶기 때문에 테두리 부분 컬러에 _emailborderColor을 넣었습니다.
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
color: _emailborderColor,
),
borderRadius: BorderRadius.circular(8)),
),
그런후 메서드 하나를 만들어줍니다.
이친구는 인풋필드를 눌렀을때 컬러색을 바꿔주는 역활을 합니다.
void _onFocusChange() {
setState(() {
_emailborderColor =
_emailfocusNode.hasFocus ? Color(0xFF4B0FFF) : Color(0xFFD1D1D1);
});
}
상태관리
자이제 이친구들이 하나만 있는게 아니자나요?
비밀번호 눌렀을때 비밀번호 인풋필드색만 변해야되고 이메일을 눌렀을때 이메일 인풋필드 색이 변해야 되니까
initState() - 위젯이 처음 생성될 때 호출되는 메서드 ,
dispose() - 위젯이 더 이상 필요하지 않을 때 호출되는 메서드
상태관리를 해주는 매서드들 두가지를 알아 둬야됩니다.
쉽게 설명하면 initState() 이걸쓰는이유는
입력 필드에 포커스가 생겼을 때 반응하려면, 이곳에서 리스너를 추가해야 합니다.
그리고 필요없어졌을때 dispose() 를 불러서 다시 기본값으로 만들어야되니까 필요한겁니다.
@override
void initState() {
super.initState();
_emailfocusNode.addListener(_onFocusChange);
}
@override
void dispose() {
_emailfocusNode.removeListener(_onFocusChange);
_emailfocusNode.dispose();
super.dispose();
}
리스너 뒤에 메서드를 넣는 이유는 그럼 뭘까요
우리가만든 색바꾸는 메서드를 넣어야 작동하니까 넣죠??
그럼 준비는 끝났습니다.
아까 만든 UI에 넣은것들을 총 정리하면
Container(
width: 428,
height: 299,
padding: EdgeInsets.symmetric(horizontal: 24),
child: Column(
children: [
Container(
width: 146,
height: 29,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/image/logo_10.png'))),
),
SizedBox(height: 48),
Column(
children: [
Container(
height: 48,
width: 428,
padding:
EdgeInsets.symmetric(vertical: 12, horizontal: 12),
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: BorderSide(
width: 1,
color: _emailborderColor,
),
borderRadius: BorderRadius.circular(8)),
),
child: TextFormField(
controller: _textController,
focusNode: _emailfocusNode,
onChanged: (text) {
setState(() {});
},
style: TextStyle(
color: Color(0xFF3D3D3D),
fontSize: 16,
fontFamily: 'Pretendard',
fontWeight: FontWeight.w500,
height: 1.0,
letterSpacing: -0.4,
),
textInputAction: TextInputAction.next,
decoration: InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
contentPadding: EdgeInsets.only(bottom: 10),
hintText: '이메일입니다.',
hintStyle: TextStyle(
color: Color(0xFF888888),
fontSize: 16,
fontFamily: 'Pretendard',
fontWeight: FontWeight.w500,
height: 1.0,
letterSpacing: -0.4,
),
suffixIcon: _textController.text.isNotEmpty
? IconButton(
onPressed: () {
_textController.clear();
setState(() {});
},
padding:
EdgeInsets.only(bottom: 10, left: 60),
icon: Icon(Icons.cancel,
color: Color(0xFF888888)))
: null),
),
),
final _textController = TextEditingController();
final FocusNode _emailfocusNode = FocusNode();
Color _emailborderColor = Color(0xFFD1D1D1); // 기본 테두리 색상
@override
void initState() {
super.initState();
_emailfocusNode.addListener(_onFocusChange);
}
@override
void dispose() {
_emailfocusNode.removeListener(_onFocusChange);
_emailfocusNode.dispose();
super.dispose();
}
void _onFocusChange() {
setState(() {
_emailborderColor =
_emailfocusNode.hasFocus ? Color(0xFF4B0FFF) : Color(0xFFD1D1D1);
});
}
쉽죠?