이번 포스팅은 ListView와 유사하지만 격자 형태로 Widget을 표현할 수 있는 GridView를 알아보자.
1. GridView를 생성하는 5개의 방법
GirdView를 생성하는 방법은 5가지가 있다.
- GridView
- GridView.builder
- GridView.count
- GridView.extent
- GridView.custom
이번 포스팅에서 다룰 것은 1~4번의 방법이다.
2. GridView 생성자 사용
GridView의 생성자의 파라미터는 ListView의 생성자와 거의 유사하다.
추가로, ListView와 GridView는 동일한 부모를 상속하고 있다.
class GridView extends BoxScrollView {
...
}
class ListView extends BoxScrollView {
...
}
Widget 형태도 기본적으로 Widget 리스트를 스크롤할 수 있게 만드는 형식이고, 둘의 차이는 자식 Widget을 어떻게 나타내는지 차이가 있는 것이다.
무튼 한 행에 3개의 자식을 갖는 GridView를 만들어 보자.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
...
home: SafeArea(
child: Scaffold(
body: makeGridView1()
)
)
);
}
Widget makeGridView1() {
return GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 4.0,
crossAxisSpacing: 8.0,
childAspectRatio: 1.0
),
children: [
Container(
color: Colors.red,
child: Text("This is Red Container!"),
),
Container(
color: Colors.blue,
child: Text("This is Blue Container!"),
),
Container(
color: Colors.yellow,
child: Text("This is Yellow Container!"),
),
Container(
color: Colors.green,
child: Text("This is Green Container!"),
),
...
],
);
}
}
위와 같은 코드를 구성하자.
ListView에서 Delegate에 대해 언급한 적이 있을 것이다.
Delegate는 "대리자" 라는 의미로, 실제 구현을 외부에 위임하고 내부에선 외부에서 구현한 메서드를 참조하는 것이다.
GridView는 Widget을 그려내기 위해 몇 가지 정보가 필요하다.
한 행 혹은 열에 몇 개의 Widget을 그려 낼 것인지, Widget 사이사이의 공간은 몇인지, 각 Widget의 크기 비율은 어떠한지이다.
이것에 대한 정보를 갖는 Delegate 객체를 외부에 위임하여 구현하도록 하고 GridView 내부에서는 이 객체를 전달받아 GridView를 구성한다.
GridView의 생성자에 전달한 "SliverGridDelegateWithFixedCrossAxisCount"를 참고하자.
위 코드를 실행하면 위와 같은 화면을 볼 수 있다.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
...
home: SafeArea(
child: Scaffold(
body: makeGridView1()
)
)
);
}
Widget makeGridView1() {
return GridView(
scrollDirection: Axis.horizontal,
...
);
}
}
만약 "scrollDirection" 파라미터에 "Axis.horizontal"를 주면 위와 같은 모습을 볼 수 있다.
3. GridView.builder
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
...
home: SafeArea(
child: Scaffold(
body: makeGridView2()
)
)
);
}
Widget makeGridView2() {
List<Color> colorList = [
Colors.white,
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow,
Colors.brown,
Colors.pink,
...
];
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 4.0,
crossAxisSpacing: 8.0,
childAspectRatio: 1.0
),
itemCount: colorList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
color: colorList[index],
child: Text(
"List item :: $index"
),
);
}
);
}
}
이번엔 GridView.builder를 사용 해 보자.
ListView처럼 Widget을 그리는 데 사용할 데이터의 리스트가 필요하다.
또한 GridView의 생성자를 사용한 것과 같이 gridDelegate가 필요하다.
물론 동일한(혹은 유사한) 결과를 확인할 수 있다.
4. GridView.count
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
...
home: SafeArea(
child: Scaffold(
body: makeGridView3()
)
)
);
}
Widget makeGridView3() {
List<Color> colorList = [
Colors.white,
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow,
Colors.brown,
Colors.pink,
...
];
return GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 6.0,
childAspectRatio: 1.0,
children: List.generate(colorList.length, (index) {
return Container(
color: colorList[index],
child: Text(
"List item :: $index"
),
);
})
);
}
}
GridView.count는 GridView 생성자를 사용한 방법과 비교하면 조금 더 편하게 사용할 수 있다.
Delegate를 넘기지 않고 파라미터에 직접 crossAxisCount, crossAxisSpacing, mainAxisSpacing, childAspectRatio을 넘기고 있다.
children을 명시적으로 받는 것은 GridView의 생성자를 사용하는 것과 동일하지만 위 예제는 List를 동적으로 생성하여 Widget을 만들어내는 방법을 사용했다.
위 방법 말고 List의 map 함수를 사용하는 방법도 좋다.
(사실 위 방법은 index가 필요해서 한 방법이고, List을 동일하게 생성하고 있어 비효율적일 수 있다.)
결과는 동일하니 첨부하지 않겠다.
5. GridView.extent
이 방법은 GridView의 생성자, GridView.count와 거의 동일하다.
하지만 가로 혹은 세로를 채울 Widget의 개수를 하나의 Widget의 너비를 통해 동적으로 구한다.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
...
home: SafeArea(
child: Scaffold(
body: makeGridView4()
)
)
);
}
Widget makeGridView4() {
List<Color> colorList = [
Colors.white,
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow,
Colors.brown,
...
];
return GridView.extent(
maxCrossAxisExtent: 100.0,
crossAxisSpacing: 4.0,
mainAxisSpacing: 8.0,
childAspectRatio: 1.0,
children: List.generate(colorList.length, (index) {
return Container(
color: colorList[index],
child: Text(
"List item :: $index"
),
);
})
);
}
}
위의 코드를 보자. 다른 방법은 crossAxisCount를 받았다면, maxCrossAxisExtent를 받고 있다.
한개의 자식 Widget의 최대 너비 혹은 높이값이다. 이 값을 사용하여 crossAxisCount를 계산해준다.
maxCrossAxisExtent 값을 변경해가며 확인해보자.
내 기준으로 maxCrossAxisExtent가 200일 때는 좌측, 100일때는 우측과 같다.
이는 디바이스의 사이즈에 따라 바뀔 수 있다.
GridView를 구성하는 방법도 어렵지 않았다.
Delegate라는 개념이 필요했지만, 단순하게 생각하면 객체를 생성해서 넘겨주는 것 뿐이다.
이제 화면을 구성할 수 있는 기본적인 Widget은 살펴보았다.
이제 "앱" 스럽게 화면을 구성할 수 있는 Widget들을 살펴보도록 할 것이다.
'개발 > Flutter' 카테고리의 다른 글
Flutter - 8. TodoList App (1) 기본 UI 구성하기 (3) | 2021.01.18 |
---|---|
Flutter - 7. Widget? Scaffold(AppBar, BottomNavigationBar, FloatingActionButton, Drawer) (0) | 2021.01.17 |
Flutter - 5. Widget? ListView (0) | 2021.01.12 |
Flutter - 4. Widget? Row, Column (0) | 2021.01.11 |
Flutter - 3. Widget? Container, Text, Image, Button (0) | 2021.01.10 |