플러터 (flutter)

Flutter에서 리스트 생성하기 (ListView, ListView.builder, ListView. separated)

CreatoMaestro 2024. 8. 11. 16:48
반응형

 

ListView는 리스트를 생성하기 위해 사용하는 위젯입니다.

거두절미하고 어떻게 사용하는지 알아보겠습니다.

 

ListView 사용하기

ListView는 기본적으로 children properties 안에 위젯을 넣으면 됩니다.

ListView(
  children: [
    //넣을 위젯
  ],
),

 

그 외에도 많은 properties가 있지만 자세한 사항은 여기서 설명하지는 않겠습니다.

자세한 사항은 아래 사이트에서 확인하시길 바랍니다.

 

ListView class - widgets library - Dart API

A scrollable list of widgets arranged linearly. ListView is the most commonly used scrolling widget. It displays its children one after another in the scroll direction. In the cross axis, the children are required to fill the ListView. If non-null, the ite

api.flutter.dev

 

ListView 사용하기

이제 ListView를 실제 코드에서 사용해 보겠습니다.

 

import 'package:flutter/material.dart';

void main() {
  runApp(const ListViewApp()); //앱을 실행하는 부분
}

class ListViewApp extends StatelessWidget {
  const ListViewApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ListView Practice',
      home: Scaffold(
        appBar: AppBar(
          title: const Text("ListView Practice"),
          centerTitle: true,
          foregroundColor: Colors.deepPurple,
        ),

        //ListView 실행 코드
        body: ListView(
          children: const [
            Text("Number 1"),
            Text("Number 2"),
            Text("Number 3"),
            Text("Number 4"),
          ],
        ),
      ),
    );
  }
}

 

저희가 봐야 할 부분은 'ListView 실행 코드' 주석 다음 부분입니다.

다른 부분은 앱을 꾸미거나 필수적으로 있어야 하는 부분이라 지금 신경 쓸 필요는 없습니다.

 

이 코드에서는 ListView 안에서 4개의 Text 위젯이 들어가 있습니다.

이를 실행하면 다음과 같이 나옵니다.

 

ListView 실행 결과

 

잘 동작합니다. 우리가 넣어준 위젯들이 리스트로 정렬되었습니다.

 

 

좀 더 리스트답게 만들기 위해 위젯을 하나 만들어 정렬해 보겠습니다.

class ListMember extends StatelessWidget {
  final String name;

  const ListMember({
    super.key,
    required this.name,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(
        horizontal: 5,
        vertical: 10,
      ),
      decoration: BoxDecoration(
        border: Border.all(
          width: 2,
          color: Colors.deepPurple,
        ),
      ),
      child: Center(
        child: Text(name),
      ),
    );
  }
}

 

이후 ListView 안에 방금 만든 위젯을 넣어줍니다.

 

body: ListView(
  children: const [
     ListMember(name: "Number 1"),
     ListMember(name: "Number 2"),
     ListMember(name: "Number 3"),
     ListMember(name: "Number 4"),
  ],
),

 

그 결과 다음과 같이 나옵니다.

 

꾸민 위젯을 이용한 리스트

 

현재 리스트 멤버가 겹쳐있는 것을 확인할 수 있습니다.

이를 해결하기 위해 두 가지 방법을 사용할 수 있습니다.


하나는 ListMember 위젯의 Container 안에 margin을 주는 방법입니다.

두 번째는 이 글에서 다룰 "ListView.separated"를 사용하는 방법입니다.

이 글에서는 이따 ListView.separated를 이용해 이 문제를 해결해 보겠습니다.

 

ListView.builder 사용하기

앞선 예제에서는 리스트 안에 4개의 위젯만 있어서 하나하나 코드로 넣어줄 수 있었습니다.

 

그러나 만약 넣어야 할 위젯이 50개, 100개가 된다면 하나하나 넣어주기 너무 힘들 것입니다.

그럴 때 사용할 수 있는 위젯이 ListView.builder입니다.

 

이 위젯은 index를 이용해 자동으로 위젯을 생성해 줍니다.

ListView.builder는 다음과 같이 사용합니다.

ListView.builder(
  itemCount: //리스트 개수,
  itemBuilder: (context, index) {
    return //위젯;
  },
),

 

itemCount property 안에는 생성할 위젯의 개수를 넣어줍니다.

만약 위젯을 List를 기반으로 만든다면 List의 length를 넣어주면 됩니다.

 

itemBuilder 안에는 context와 index를 매개변수로 받는 함수를 넣어줍니다.

이 함수 안에서 위젯을 return 해주면 됩니다.

 

이 함수를 코드 안에서 실제로 사용해 봅시다.

위의 코드에서 ListView 위젯만 ListView.builder로 바뀌었습니다.

 

import 'package:flutter/material.dart';

void main() {
  runApp(const ListViewApp()); //앱을 실행하는 부분
}

class ListViewApp extends StatelessWidget {
  const ListViewApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ListView Practice',
      home: Scaffold(
        appBar: AppBar(
          title: const Text("ListView Practice"),
          centerTitle: true,
          foregroundColor: Colors.deepPurple,
        ),

        //ListView 실행 코드
        body: ListView.builder(
          itemCount: 100,
          itemBuilder: (context, index) {
            return ListMember(name: "Number $index");
          },
        ),
      ),
    );
  }
}

class ListMember extends StatelessWidget {
  final String name;

  const ListMember({
    super.key,
    required this.name,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(
        horizontal: 5,
        vertical: 10,
      ),
      decoration: BoxDecoration(
        border: Border.all(
          width: 2,
          color: Colors.deepPurple,
        ),
      ),
      child: Center(
        child: Text(name),
      ),
    );
  }
}

 

위 코드에서는 리스트에 들어갈 위젯 개수를 100으로 설정했고,

ListMember 위젯을 반환하도록 설정했습니다.

 

실행 결과는 다음과 같습니다.

 

ListView.builder 실행 결과

 

많은 위젯이 리스트로 생성된 것을 확인할 수 있습니다.

스크롤을 이용해 화면을 아래로 내리면 리스트가 100개 생성된 것을 확인할 수 있습니다.

 

 

ListView.separated 사용하기

마지막으로 'ListView.separated'에 대해 살펴보겠습니다.

앞서 우리가 리스트를 생성할 때 리스트가 겹쳐서 나오는 문제가 있었습니다.

ListView.separated는 이런 문제를 쉽게 해결해 줍니다.

 

ListView.separated(
  itemCount: //위젯 개수,
  itemBuilder: (context, index) {
    return //리스트에 넣을 위젯;
  },
  separatorBuilder: (context, index) {
    return //분리용 위젯;
  },
),

 

ListView.separated는 separatorBuilder가 추가로 들어갑니다.

이 property는 리스트 멤버 사이에 들어갈 위젯을 생성해 줍니다.

 

이해를 위해 코드 안에 적용해 보겠습니다.

ListView.builder 대신 Listview.separated가 들어갔습니다.

 

import 'package:flutter/material.dart';

void main() {
  runApp(const ListViewApp()); //앱을 실행하는 부분
}

class ListViewApp extends StatelessWidget {
  const ListViewApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ListView Practice',
      home: Scaffold(
        appBar: AppBar(
          title: const Text("ListView Practice"),
          centerTitle: true,
          foregroundColor: Colors.deepPurple,
        ),

        //ListView 실행 코드
        body: ListView.separated(
          itemCount: 100,
          itemBuilder: (context, index) {
            return ListMember(name: "Number $index");
          },
          separatorBuilder: (context, index) {
            return const SizedBox(
              height: 10,
            );
          },
        ),
      ),
    );
  }
}

class ListMember extends StatelessWidget {
  final String name;

  const ListMember({
    super.key,
    required this.name,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(
        horizontal: 5,
        vertical: 10,
      ),
      decoration: BoxDecoration(
        border: Border.all(
          width: 2,
          color: Colors.deepPurple,
        ),
      ),
      child: Center(
        child: Text(name),
      ),
    );
  }
}

 

separatorBuilder 안에 높이(height)가 10인 SizedBox가 있습니다.

이 SizedBox가 ListMember 위젯 사이사이에 들어가게 됩니다.

 

실행 결과 다음과 같이 나옵니다.

 

ListView.separated 실행 결과

 

실행 결과 위젯 사이사이에 공간이 생긴 것을 볼 수 있습니다.

이 공간은 빈 공간이 아닌 SizedBox가 들어가 있는 공간입니다.

SizedBox가 두 ListMember 위젯 사이에 들어가 서로 떨어져 있는 것처럼 보이는 것입니다.

Widget inspector를 이용한 구조 확인

 

Widget inspector를 확인하면 두 ListMember 위젯 사시에 SizedBox가 들어간 것을 확인할 수 있습니다. 

 

반응형