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 |