반응형
Overview
- 실시간 검색기능으로 검색어와 일치하는 항목 출력
ListView 목록 구현 포스팅 관련
- 해당 포스팅은 이전 포스팅의 ListView+Card 활용 예시의 소스코드를 이용합니다.
- ListView에 목록 표시 관련 포스팅은 아래의 링크를 확인해주세요.
- 2023.04.28 - [Programming/Flutter] - Flutter - ListView, Card - 스크롤 가능한 목록 표시, 목록 선택시 특정 목록 내용 보여주기
포스팅에 사용된 예시 프로젝트 파일 다운로드
- 예시를 위한 프로젝트 파일은 깃허브에서 다운로드 가능합니다.
- '2_add_search_example' 폴더를 확인해주세요.
- https://github.com/luvris2/flutter_memo_app
StatefulWidget 위젯
설명
- 변경 가능한 상태를 가진 위젯
- 위젯이 빌드될 때 동기적으로 읽을 수 있음
- 위젯의 수명동안 변경될 수 있음
- 상태 변경 시, State.setState를 사용하여 State에 즉시 알리도록 코딩
- StatefulWidget을 확장할 때마다 createState 호출
* StatelessWidget은 주어진 특정 구성 및 주변 상태에 항상 동일한 방식으로 빌드되는 위젯
구문
void main() {
runApp(MyApp());
}
// 메인 앱에서 statefulWidget 클래스 상속
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
// 상태 변경을 위해 클래스 오버라이딩
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// 앱을 동적으로 변경할 코드 작성
}
- extends StatefulWidget : 앱의 동적 표시를 위해 변경 가능한 위젯 상속
- createState() : 위젯에 대한 변경 가능한 상태로 설정
- 변수나 클래스 앞에 언더바(_)가 있는 이유?
- private 형태임을 암시하는 키워드, 즉 _MyAppState 클래스는 공개되지 않는 형태임을 암시
설계 및 코딩
요구사항
- 텍스트 필드를 추가하여 검색어를 입력할 수 있도록 함
- 메인 클래스를 StatefulWidget 클래스에 상속
- createState를 이용하여 앱이 동적으로 작동하도록 변경 가능 상태로 설정 (검색을 위해)
- 리스트뷰에 표시되어 있는 항목의 문자열과 검색어가 맞는지 확인
- 검색어가 일치할 경우 일치한 항목을 리스트뷰에 출력
- 검색어가 일치하지 않을 경우 아무런 항목을 반환하지 않음
- 검색어가 없으면 모든 항목 표시
코드 설계
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
// 검색어
String searchText = '';
// 리스트뷰에 표시할 내용
List<String> items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];
List<String> itemContents = [
'Item 1 Contents',
'Item 2 Contents',
'Item 3 Contents',
'Item 4 Contents'
];
// 검색을 위해 앱의 상태를 변경해야하므로 StatefulWidget 상속
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
MyAppState createState() => MyAppState();
}
// 메인 클래스의 상태 상속
class MyAppState extends State<MyApp> {
// 리스트뷰 카드 클릭 이벤트 핸들러
void cardClickEvent(BuildContext context, int index) {
String content = itemContents[index];
Navigator.push(
context,
MaterialPageRoute(
// 정의한 ContentPage의 폼 호출
builder: (context) => ContentPage(content: content),
),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MemoApp', // 앱의 아이콘 이름
home: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Search Example'), // 앱 상단바 설정
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(20.0),
child: TextField(
decoration: InputDecoration(
hintText: '검색어를 입력해주세요.',
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
searchText = value;
});
},
),
),
Expanded(
child: ListView.builder(
// items 변수에 저장되어 있는 모든 값 출력
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
// 검색 기능, 검색어가 있을 경우
if (searchText.isNotEmpty &&
!items[index]
.toLowerCase()
.contains(searchText.toLowerCase())) {
return SizedBox.shrink();
}
// 검색어가 없을 경우, 모든 항목 표시
else {
return Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.elliptical(20, 20))),
child: ListTile(
title: Text(items[index]),
onTap: () => cardClickEvent(context, index),
),
);
}
},
),
),
],
),
),
);
}
}
// 선택한 항목의 내용을 보여주는 추가 페이지
class ContentPage extends StatelessWidget {
final String content;
const ContentPage({Key? key, required this.content}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Content'),
),
body: Center(
child: Text(content),
),
);
}
}
실행
참고
반응형