Foggy day

[Flutter] GridView - 사용법 본문

Flutter/Flutter widget

[Flutter] GridView - 사용법

jinhan38 2023. 3. 24. 00:56

 

 

이번 포스팅에서는 GridView 위젯에 대해 알아보겠습니다. GridView는 ListView와 동일한 특성들이 많습니다. 그래서 ListView에는 없는 내용들만 다루겠습니다. 중복된 내용들은 ListView 포스팅을 참고해 주시기 바랍니다. 

 

https://jinhan38.tistory.com/134

 

[Flutter] ListView - 사용법

이번 포스팅에서는 ListView 위젯에 대해 알아보겠습니다. 1. 기본 사용법 2. shrinkWrap 3. cacheExtent 4. itemExtent, prototypeItem 5. ListView.builder, ListView.seperated 1. 기본 사용법 ListView의 기본 사용법은 간단합

jinhan38.com

 

 

 

1. 기본 사용법(GridView.count)
2. SliverGridDelegate
3. GridView.extent
4. GridView.builder

 

 

 

1. 기본 사용법(GridView.count)

GridView는 한 가지 함수를 제외하고는 모두 SliverGridDelegate를 필요로합니다. 1번에서는 SliverGridDelegate 없이 사용해 보고 2번부터 SliverGridDelegate를 배운 후 다른 GridView들을 사용해 보겠습니다. 

GridView.count를 사용하면 SliverGridDelegate를 사용하지 않고 GirdView를 만들 수 있습니다.

crossAxisCount 항목에 기준축(main)과 교차되는(cross) 축에 몇 개의 타일을 사용할지 입력합니다.

기준 축은 scrollDirection 특성으로 변경할 수 있습니다. 

 

  Widget _gridViewCount() {
    return GridView.count(
      scrollDirection: Axis.vertical,
      crossAxisCount: 4,
      children: [
        ..._listItem(),
      ],
    );
  }

 

 

 

2. SliverGridDelegate

SliverGridDelegate는 GridView에 들어가는 타일들의 레이아웃을 계산합니다. SliverGridDelegate는 추상 클래스이기 때문에 실제로는 SliverGridDelegateWithFixedCrossAxisCount, SliverGridDelegateWithMaxCrossAxisExtent 두 클래스를 사용합니다. 

 

  • SliverGridDelegateWithFixedCrossAxisCount : 기준 축과 교차되는 축의 개수를 결정합니다. 세로 스크롤이라면 가로로 몇 개의 타일이 들어갈지 설정할 수 있습니다. 
crossAxisCount : cross되는 축에 들어갈 타일의 개수
crossAxisSpacing : cross되는 축의 타일들 사이의 간격
mainAxisSpacing : 기준 축의 타일들 사이의 간격
childAspectRatio : 기준 축과 크로스되는크로스 되는 축의 비율.  2를 입력하면 기준축의 사이즈보다 크로스 되는 축의 사이즈가 2배. (ex. 기준축이 세로일 경우, 가로 사이즈가 세로 사이즈의 2배)
mainAxisExtent : main축(기준축)의 사이즈(mainAxisExtent를 입력하면 childAspectRatio는 무시됩니다.)

 

  Widget _body() {
    return GridView(
      gridDelegate: _sliverGridDelegate(),
      children: [
        ..._listItem(),
      ],
    );
  }

  SliverGridDelegate _sliverGridDelegate() {
    return const SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 4,
      crossAxisSpacing: 10,
      mainAxisSpacing: 30,
      mainAxisExtent: 150,
      // childAspectRatio: 2,
    );
  }

 

 

 

  • SliverGridDelegateWithMaxCrossAxisExtent : main 축과 cross 된 축의 최대 사이즈를 입력해서 타일의 레이아웃을 계산합니다.
    maxCrossAxisExtent : cross축 한 개 타일의 최대 사이즈를 지정합니다. 
    만약에 가로 사이즈가 500이고, maxCrossAxisExtent를 150으로 입력한다면  125 넓이의 타일 4개를 만듭니다.
    가로 사이즈가 300이고, maxCrossAxisExtent를 100~140사이로 입력한다면 3개의 타일이 만들어집니다. 
    가로 사이즈가 300이고, maxCrossAxisExtent를 150으로 입력한다면 2개의 타일이 만들어집니다. 
    maxCrossAxisExtent에 입력한 값으로 타일 사이즈를 지정하는 것이 아닙니다. 가로넓이와 maxCrossAxisExten를 계산해서 만들 수 있는 최대한의 타일 크기로 만들어집니다. 

    mainAxisExtent : 기준축의 사이즈
    mainAxisSpacing : 기준축 타일의 간격
    crossAxisSpacing : 교차축 타일의 간격 
  Widget _body() {
    return SizedBox(
      width: 300,
      child: GridView(
        gridDelegate: _sliverGridDelegate(),
        children: [
          ..._listItem(),
        ],
      ),
    );
  }

  SliverGridDelegate _sliverGridDelegate() {
    return const SliverGridDelegateWithMaxCrossAxisExtent(
      maxCrossAxisExtent: 140,
      mainAxisExtent: 200,
      mainAxisSpacing: 10,
      // crossAxisSpacing: 10,
    );
  }

 

 

 

3. GridView.extent

GridView.extent는 2번에서 다룬 SliverGridDelegateWithMaxCrossAxisExtent를 확장함수로 구현해 놓은 함수입니다. maxCrossAxisExtent값을 받아서 가로 축의 개수를 설정할 수 있습니다. 

 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("GridViewScreen"),
      ),
      body: _gridViewExtent(),
    );
  }

  Widget _gridViewExtent() {
    return GridView.extent(
      maxCrossAxisExtent: 150,
      children: [
        ..._listItem(),
      ],
    );
  }

 

 

 

 

4. GridView.builder

GridView.builder는 ListView.builder와 같은 형태입니다. itemBuilder 함수를 각각의 타일들을 만들 수 있습니다. 

그리고 itemCount를 꼭 입력해야 합니다. 그렇지 않으면 몇개의 자식 위젯들을 생성할지 알 수 없기 때문입니다. 

 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("GridViewScreen"),
      ),
      body: _gridViewBuilder(),
    );
  }
  
  Widget _gridViewBuilder() {
    return GridView.builder(
      itemCount: _listItem().length,
      gridDelegate: _sliverGridDelegate(),
      itemBuilder: (context, index) {
        return _listItem()[index];
      },
    );
  }

 

itemBuilder함수의 형태.

Widget을 반환하여 context와 index를 전달합니다.

Widget? Function(BuildContext context, int index);

 

 

 

 

Full code

import 'dart:math';

import 'package:flutter/material.dart';

class GridViewScreen extends StatefulWidget {
  const GridViewScreen({Key? key}) : super(key: key);

  @override
  State<GridViewScreen> createState() => _GridViewScreenState();
}

class _GridViewScreenState extends State<GridViewScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("GridViewScreen"),
      ),
      body: _gridViewBuilder(),
    );
  }

  Widget _gridViewCount() {
    return GridView.count(
      scrollDirection: Axis.vertical,
      crossAxisCount: 4,
      children: [
        ..._listItem(),
      ],
    );
  }

  Widget _gridViewExtent() {
    return GridView.extent(
      maxCrossAxisExtent: 150,
      children: [
        ..._listItem(),
      ],
    );
  }

  Widget _gridViewBuilder() {
    return GridView.builder(
      itemCount: _listItem().length,
      gridDelegate: _sliverGridDelegate(),
      itemBuilder: (context, index) {
        return _listItem()[index];
      },
    );
  }

  Widget _body() {
    return GridView(
      gridDelegate: _sliverGridDelegate(),
      children: [
        ..._listItem(),
      ],
    );
  }

  SliverGridDelegate _sliverGridDelegate() {
    // return const SliverGridDelegateWithMaxCrossAxisExtent(
    //   maxCrossAxisExtent: 140,
    //   mainAxisExtent: 200,
    //   mainAxisSpacing: 10,
    //   // crossAxisSpacing: 10,
    // );
    return const SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 4,
      crossAxisSpacing: 10,
      mainAxisSpacing: 30,
      mainAxisExtent: 150,
      // childAspectRatio: 2,
    );
  }

  List<Widget> _listItem() {
    List<Widget> widgets = [];
    for (int i = 0; i < 30; i++) {
      widgets.add(
        Container(
          color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
        ),
      );
    }
    return widgets;
  }
}