여러 SNS 앱들은 사용자가 자신들의 이야기를 앱에 적어 기록할 수 있게 되어있습니다. 지난 포스팅에서 다뤘던 Text위젯은 정해진 글만 보여주는데요. 사용자가 앱에 글을 적을 수 있도록 할 수 있는 방식으로 Flutter에서는 TextField를 이용합니다.
TextField위젯은 Flutter에서 기본으로 제공되는 위젯입니다. 그냥 선언만 하게 되면 아래와 같은 모습의 TextField를 확인할 수 있습니다.
import 'package:flutter/material.dart';
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TextField'),
),
body: Center(child: TextField()),
);
}
}
TextField는 수많은 프로퍼티를 가지고 있습니다. 전부다 다룰 순 없고, 가장 기본이 되는 프로퍼티 몇가지를 소개합니다.
1. decoration
아무것도 변경하지 않고, TextFeild를 생성하면 가장 기본적인 위 모습이 나옵니다. 빈 화면에 힌트처리된 줄만 보입니다. 기본적인 모습도 앱에서 활용 가능할 경우가 있지만, 대부분의 앱은 기본적인 형식보다는 커스터마이징해서 사용하게 됩니다. 이를 위해서 TextField위젯의 decoration프로퍼티를 이용하겠습니다.
import 'package:flutter/material.dart';
class TextFieldPage extends StatelessWidget {
const TextFieldPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TextField'),
),
body: Center(
child: TextField(
decoration:
)),
);
}
}
decoration프로퍼티에 InputDecoration을 전달합니다. InputDecoration을 이용해서 border, 즉, 테두리를 없앨 수 있습니다. 아래와 같이 입력합니다.
import 'package:flutter/material.dart';
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TextField'),
),
body: Center(
child: TextField(
decoration: InputDecoration(border: InputBorder.none),
)),
);
}
}
핫 리로딩을 해주면, 아래와 같은 모습이 됩니다.
아무것도 없는 것 같지만, 사실, 왼쪽 중앙부분에 커서가 보일겁니다. 이는 가장 깨끗한 모습의 TextField입니다. 지금부터, 실제로 앱의 UI로 어울리는 모습으로 바꿔보겠습니다. 어떤 앱의 로그인화면을 꾸며볼 건데요. Flutter로 제작되는 앱은 로그인화면을 구성할 때, TextField로 구성할 수 있습니다. 그 이전에 Center위젯을 Column으로 변경하고, 2개의 TextField를 세로로 가운데에 정렬시켜 배치하겠습니다.
import 'package:flutter/material.dart';
class App extends StatelessWidget {
const App({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TextField'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextField(
decoration:
InputDecoration(
border: InputBorder.none, hintText: '아이디'),
),
TextField(
decoration:
InputDecoration(border: InputBorder.none, hintText: '비밀번호'),
),
]),
),
);
}
}
이렇게 되면, 화면구성이 아래처럼 변합니다.
지금부터 아이디와 비밀번호 로그인 화면을 만들건데, 이렇게 생성한 코드는 디자인을 위해 겹쳐지는 부분이 많아지기 때문에, 컴포넌트로써, CustomTextField로 생성한 후, 사용하는 것이 불필요한 코드 수정을 방지할 수 있습니다. 하지만 이번 포스팅에서는 그냥 하겠습니다.
이 모습에서 다양한 요소들을 확인할 수 있습니다. 아이디에 해당하는 코드를 함께 보면서 알아봅시다.
...
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.account_circle_rounded), // 앞쪽 아이콘
suffixIcon: Icon(Icons.close), // 뒤쪽 아이콘
fillColor: Colors.white, // 채우기 색
filled: true, // 채우기 유무 default = false
labelStyle: TextStyle(color: Colors.black,
focusedBorder: OutlineInputBorder(), // 활성화 테두리
enabledBorder: // 비활성화 테두리
OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
border: InputBorder.none,
labelText: '아이디'),
);
여기서 눈 여겨서 봐야할점은 filled는 기본으로 false이기 때문에, true값을 주지 않으면, 적용이 안됩니다. 제가 처음에 헤매어서 언급합니다. 아이디의 경우는 기본 입력 키보드지만, 비밀번호는 텍스트 대체와 숫자 키패드인것이 보이죠?? 비밀번호 코드 한번 보겠습니다.
TextField(
obscureText: true, // 텍스트 대체 여부
keyboardType: TextInputType.number // 키보드 타입
decoration: InputDecoration(
...
);
obscureText라는 프로퍼티에 true값을 할당하게 되면, 텍스트 대체를 할 수 있어서 비밀번호와 같은 field를 생성하기에 적절합니다. 그리고 keyboardType은 TextInputType을 인자로 받게 되는데, 이 타입에 따라서 숫자, 이메일 주소 키타입 등을 생성할 수 있습니다. 그 외에 더 다양한 기능이 있기에 직접 생성해보는 것을 추천합니다.
그리고 textField외의 UI 영역을 클릭하면 보통의 앱은 비활성화가 되는 것을 알 수 있습니다.
...
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
backgroundColor: Colors.grey[100],
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
...
Scaffold 영역을 GestureDetector라는 감지 위젯으로 감싸주고, onTap이라는 Function() 프로퍼티에 위처럼 설정해주면, textField가 아닌 UI영역을 터치하면 자동으로 unfocus가 됩니다.