플러터를 활용한 검색창 UI 개선: 포커스에 따른 컬러 변화 구현
TextField와 InputDecoration 위젯을 사용한 검색창 UI 구현
이번 글에선 플러터를 활용해 검색창의 사용자 경험을 개선하는 방법에 대해 이야기하려고 합니다. 이번 포스팅의 핵심은 바로 "검색창의 포커스에 따라 아이콘과 테두리 색이 변화하는 기능"입니다. 이 기능을 통해 사용자는 검색창이 현재 활성화되어 있는지 쉽게 파악할 수 있게 됩니다.
첫 번째로 보실 부분은 `_SearchPageState` 클래스 내부에 선언된 `_focusNode`라는 인스턴스입니다. 이는 `FocusNode` 클래스의 인스턴스로, 해당 위젯이 현재 포커스를 가지고 있는지 아닌지를 판단하는 역할을 합니다. 초기에는 `initState()` 메소드에서 `_focusNode`를 생성하고, `_onFocusChange` 메소드를 통해 포커스가 변화할 때마다 화면을 다시 그릴 수 있도록 설정하였습니다.
다음으로 `_onFocusChange` 메소드입니다. 이 메소드는 `_focusNode`의 포커스 상태가 변경될 때마다 호출되며, `setState()`를 호출해 화면을 다시 그립니다. 이를 통해 검색창이 포커스를 얻거나 잃을 때마다 아이콘과 테두리의 색상을 실시간으로 업데이트할 수 있습니다.
그럼 실제로 어떻게 색상이 변화하는지 살펴봅시다. `build()` 메소드 내에서는 `_focusNode.hasFocus`의 값에 따라 아이콘의 색상을 결정합니다. 만약 포커스가 있으면 아이콘 색상은 파란색, 없으면 회색으로 설정하였습니다. 이렇게 설정된 색상은 `TextField`의 `decoration` 프로퍼티에서 `Icon(Icons.clear, color: iconColor)`와 같은 형태로 사용되어 아이콘 색상이 실제로 반영됩니다.
마지막으로, 테두리 색상 역시 비슷한 방법으로 변경할 수 있습니다. `TextField`의 `decoration` 프로퍼티에서 `focusedBorder` 옵션을 사용하여 포커스가 있을 때 테두리의 스타일을 정의할 수 있습니다. 여기서는 파란색으로 설정하였습니다.
이렇게 간단한 코드 변경만으로도 사용자의 경험을 크게 향상시킬 수 있습니다. 포커스에 따라 색상이 변경되는 검색창은 사용자에게 직관적인 인터페이스를 제공하며, 이를 통해 사용자는 검색창의 상태를 쉽게 이해할 수 있습니다.
코드는 아래를 참조해주세요.
import 'package:flutter/material.dart';
class SearchApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Search Page',
home: SearchPage(),
);
}
}
class SearchPage extends StatefulWidget {
@override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
String searchQuery = '';
List<String> searchResults = [];
late FocusNode _focusNode;
void search(String searchInput) {
// 여기에 검색 로직
setState(() {
searchResults = List<String>.generate(5, (int index) {
return '$searchInput result $index';
});
});
}
void clearSearch() {
setState(() {
searchQuery = '';
searchResults = [];
});
}
@override
void initState() {
super.initState();
_focusNode = FocusNode();
_focusNode.addListener(_onFocusChange);
}
void _onFocusChange() {
setState(() {}); // Focus 변화 시 화면을 다시 그립니다.
}
@override
void dispose() {
_focusNode.removeListener(_onFocusChange);
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
Color iconColor = _focusNode.hasFocus ? Colors.blue : Colors.grey;
return Scaffold(
appBar: AppBar(
title: Text(
'검색',
style: TextStyle(
color: Colors.black,
),
),
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
color: Colors.grey,
onPressed: () {
Navigator.pop(context);
},
),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(children: [
TextField(
focusNode: _focusNode,
onChanged: (value) {
searchQuery = value;
search(value);
},
decoration: InputDecoration(
hintText: '검색할 공연이름을 입력해주세요!',
suffixIcon: IconButton(
onPressed: clearSearch,
icon: Icon(Icons.clear, color: iconColor),
),
prefixIcon: IconButton(
onPressed: () {
search(searchQuery);
},
icon: Icon(Icons.search, color: iconColor),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
),
// 포커스가 있을 때 테두리 색상
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
borderSide: BorderSide(
color: Colors.blue, // 원하는 색상으로 변경
),
),
),
),
Expanded(
child: ListView.builder(
itemCount: searchResults.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(searchResults[index]),
);
},
),
),
]),
),
);
}
}
'공부기록 > Flutter' 카테고리의 다른 글
[Flutter] 텍스트 길이가 길 경우 말 줄임표 사용하는 방법 (1) | 2023.07.13 |
---|---|
[Flutter] 이미지 없을 때 기본 이미지로 대체하기 (0) | 2023.07.12 |
Flutter로 웹 앱 실행하기: 사용자 지정 호스트네임과 포트 설정 방법 (0) | 2023.07.08 |
[Flutter] ListView 재사용하기(재사용 가능한 Widget 만들기) (0) | 2023.07.05 |
[Flutter] AppBar, BottomNavigator 구현(상단,하단은 고정 & body만 바뀌도록) (0) | 2023.07.05 |