
Flutter에서 ListView 재사용하기
똑같은 형태의 Widget을 구현할 때는 Widget을 재사용 할 수 있다.
bottomNavigatior로 탭하여 화면을 바꾸는 것은 아래 링크에서 확인해주세요.
2023.07.05 - [공부기록/Flutter] - [Flutter] AppBar, BottomNavigator 구현(상단,하단은 고정 & body만 바뀌도록)
이번 글에서는 Widget을 재사용하는 방법에 대해 알아보겠습니다.
verticalList.dart
VerticalListWidget
은 StatefulWidget이다. 이 위젯은 수직 스크롤이 가능한 리스트를 생성하며, 각 아이템은 제목, 기간, 장소/날짜 정보, 그리고 이미지로 구성된다.initState
메서드에서는 widget.itemList
을 기반으로 _isAlarmActiveList
를 초기화한다. itemList
의 각 아이템의 alarmyn
값이 'Y'인 경우 _isAlarmActiveList
의 해당 인덱스를 true로 설정한다.build
메서드에서는 ListView.builder를 사용하여 아이템을 생성. 각 아이템은 Row 위젯으로 구성되며, 좌측에는 텍스트 정보를, 우측에는 이미지를 표시한다. 알림 아이콘은 GestureDetector를 사용하여 토글 기능을 구현하였으며, _isAlarmActiveList
의 상태에 따라 아이콘의 색상이 변경된다.
VerticalListWidget은 itemList
속성을 받아 수직 리스트를 생성하며, 알림 아이콘을 토글할 수 있는 기능을 제공한다.
import 'package:flutter/material.dart';
class VerticalListWidget extends StatefulWidget {
final List<Map<String, String>> itemList;
VerticalListWidget({required this.itemList});
@override
_VerticalListWidgetState createState() => _VerticalListWidgetState();
}
class _VerticalListWidgetState extends State<VerticalListWidget> {
late List<Map<String, String>> itemList;
late List<bool> _isAlarmActiveList;
@override
void initState() {
super.initState();
itemList = widget.itemList; // Access widget property in initState
_isAlarmActiveList = List<bool>.filled(itemList.length, false);
// Initialize alarm toggle state based on alarmyn value
for (int i = 0; i < itemList.length; i++) {
if (itemList[i]['alarmyn'] == 'Y') {
_isAlarmActiveList[i] = true;
}
}
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: itemList.length,
itemBuilder: (context, index) {
//bool isAlarmActive = itemList[index]['alarmyn'] == 'Y';
bool isAlarmActive = _isAlarmActiveList[index];
return Container(
padding: EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
flex: 8,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
itemList[index]['title'].toString(),
style: TextStyle(
fontSize: 24.0,
color: Colors.black,
),
),
SizedBox(height: 8.0),
Text(
itemList[index]['period'] == null
? ''
: itemList[index]['period'].toString(),
style: TextStyle(
fontSize: 16.0,
color: Colors.grey,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
itemList[index]['location'] == null
? itemList[index]['dt'].toString()
: itemList[index]['location'].toString(),
style: TextStyle(
fontSize: 16.0,
color: Colors.grey.shade700,
),
),
Visibility(
visible: itemList[index]['location'] ==
null, //티켓오픈소식일때만 보이도록
child: GestureDetector(
onTap: () {
setState(() {
//isAlarmActive = !isAlarmActive;
_isAlarmActiveList[index] =
!_isAlarmActiveList[index];
});
},
child: Padding(
padding: EdgeInsets.only(right: 18.0),
child: Icon(
isAlarmActive
? Icons.notifications_active
: Icons.notifications_none_outlined,
color: isAlarmActive
? Colors.yellow
: Colors.grey.shade700,
),
),
),
)
]),
],
),
),
Expanded(
flex: 2,
child: Image.network(
itemList[index]['url'].toString(),
fit: BoxFit.cover,
),
),
],
),
);
},
);
}
}
tab1.dart
Tab1Page
는 StatelessWidget이다. 이 페이지는 탭 1 리스트를 보여주는 화면이다. itmList
는 맵 형식으로 이루어진 아이템 리스트입니다. 각 아이템은 제목, 기간, 장소, 이미지 URL로 구성되어 있다. build
메서드에서는 Column 위젯을 사용하여 화면을 구성한다. 제목을 나타내는 텍스트와 수직 스크롤 가능한 리스트를 포함하고 있다. 리스트는 VerticalListWidget
위젯을 사용하여 생성되며, itemList
속성에 itmList
를 전달하여 아이템 리스트를 표시한다.
이 페이지는 '탭1 리스트'라는 제목과 수직 스크롤 가능한 아이템 리스트를 가진 화면을 나타낸다.
import 'package:flutter/material.dart';
import 'package:musicalapp/verticalList.dart';
class Tab1Page extends StatelessWidget {
List<Map<String, String>> itmList = [
{
'title': 'Title 1',
'period': '2023-06-19~2023-06-30',
'location': 'Loc 1',
'url':
'https://cdn.pixabay.com/photo/2023/05/19/15/40/man-8004816_1280.jpg'
},
{
'title': 'Title 2',
'period': '2023-06-19~2023-06-30',
'location': 'Loc 2',
'url':
'https://cdn.pixabay.com/photo/2023/06/17/22/51/shoes-8070908_640.jpg'
},
{
'title': 'Title 3',
'period': '2023-06-19~2023-06-30',
'location': 'Loc 3',
'url':
'https://cdn.pixabay.com/photo/2023/05/30/17/20/woman-8029209_640.jpg'
}
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'탭1 리스트',
style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
),
),
Expanded(child: VerticalListWidget(itemList: itmList)),
],
),
);
}
}
tab2.dart
tab1.dart와 동일한 구조를 가졌다. itmList
구조만 다르다.
import 'package:flutter/material.dart';
import 'package:musicalapp/verticalList.dart';
class Tab2Page extends StatelessWidget {
List<Map<String, String>> itmList = [
{
'title': 'Title 1',
'dt': '2023-06-19~2023-06-30',
'alarmyn': 'Y',
'url':
'https://cdn.pixabay.com/photo/2016/02/21/12/09/heart-1213475_1280.jpg'
},
{
'title': 'Title 2',
'dt': '2023-06-19~2023-06-30',
'alarmyn': 'Y',
'url':
'https://cdn.pixabay.com/photo/2019/06/20/09/26/underwater-4286600_640.jpg'
},
{
'title': 'Title 3',
'dt': '2023-06-19~2023-06-30',
'alarmyn': 'N',
'url':
'https://cdn.pixabay.com/photo/2017/09/02/15/10/lighthouse-2707528_640.jpg'
}
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'탭2 리스트',
style: TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
),
),
Expanded(child: VerticalListWidget(itemList: itmList)),
],
),
);
}
}
자주 사용하는 ListView 형태를 미리 구현해두고, 데이터만 넘겨주는 방식으로 재사용을 할 수 있다.
(정식으로 공부를 해서 작성하는 코드가 아니므로 더 좋은 방법이 있을 수 도 있습니다. 더 효율적인 방법이 있다면 댓글로 알려주시면 감사드리겠습니다!)
'공부기록 > Flutter' 카테고리의 다른 글
[Flutter] 포커스에 따른 input 박스 색상 변화 구현 (0) | 2023.07.09 |
---|---|
Flutter로 웹 앱 실행하기: 사용자 지정 호스트네임과 포트 설정 방법 (0) | 2023.07.08 |
[Flutter] AppBar, BottomNavigator 구현(상단,하단은 고정 & body만 바뀌도록) (0) | 2023.07.05 |
[Flutter] 반응형 모바일 배너 만들기(슬라이더) (0) | 2023.07.04 |
Flutter 유용한 Extensions(확장팩) 추천(Flutter Widget Snippets, Flutter Tree) (0) | 2023.07.02 |