스터디/Flutter+Dart

Flutter 리스트 뷰 (ListView)

Dalmangyi 2019. 7. 25.

어떠한 정보들을 스크롤 방향으로 나열한 뷰를 말합니다 

아니 여기선 Widget이라고 해야되나...?....

 

 

1. 정적인 아주 간단한 리스트 뷰

Widget을 직접 넣어준 만큼 리스트뷰에서 보여줘 보자

 

1.1 소스코드

import 'package:flutter/material.dart';  

void main(){
  runApp(
    MaterialApp(
        home: ListView(
          padding: const EdgeInsets.all(8.0),
          children: <Widget>[
            Container(
              height: 50,
              color: Colors.amber[600],
              child: const Center(child: Text('Entry A')),
            ),
            Container(
              height: 50,
              color: Colors.amber[500],
              child: const Center(child: Text('Entry B')),
            ),
            Container(
              height: 50,
              color: Colors.amber[100],
              child: const Center(child: Text('Entry C')),
            ),
          ],
        )
    )
  );
}

높이가 50인 Container 위젯 3개를 리스트뷰의 children으로 설정했다.

첫번째 Container는 'Entry A' 라는 텍스트를 가지며, 색상은 cmber[600]으로 설정되어 있다 

두번째 Container는 'Entry B' 라는 텍스트를 가지며, 색상은 cmber[500]으로 설정되어 있다 

세번째 Container는 'Entry C' 라는 텍스트를 가지며, 색상은 cmber[100]으로 설정되어 있다 

 

1.2 실행화면

리스트뷰에서 최대로 한쪽 방향으로 스크롤을 당기면 나타나는 Drawer도 잘 표현되고 있다. 

실행화면 gif

 

 

 

2. 정적인 리스트 뷰에 서로 다른 Widget을 설정해 보자

안드로이드나 아이폰에서는 리스트뷰의 각 행 (또는 Cell) 마다 다른 형태를 지원할때 ViewHolder마다 각기 다른 코딩으로 꾸며주곤 했는데.. flutter는 Widget 기반이니 얼마나 편리해졌는지 한번 봐보도록 하자

 

2.1 소스코드

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';

void main(){
  runApp(
    MaterialApp( 
        home: ListView(
          padding: const EdgeInsets.all(8.0),
          children: <Widget>[
            Center(child: Text('Entry A')),
            Container(
              height: 50,
              color: Colors.amber[500],
              child: const Center(child: Text('Entry B')),
            ),
            CachedNetworkImage(
              imageUrl: "http://via.placeholder.com/250x250",
              placeholder: (context, url) => new CircularProgressIndicator(),
              errorWidget: (context, url, error) => new Icon(Icons.error),
            ),
          ],
        )
      )
  );
} 

cached_network_image (CachedNetworkImage)를 세팅 방법을 모른다면 dalgonakit.tistory.com에서 찾아보도록 하자

 

첫번째는 Center-Text Widget으로 설정하였고

두번째는 Container-Center-Text Widget으로 설정

세번째는 CachedNetworkImage로 설정하였다.

 

2.2 실행화면

서로 각기 다른 Widget을 가진 리스트뷰에서 최대로 한쪽 방향으로 스크롤을 당기면 나타나는 Drawer도 잘 표현되고 있다. 

 

실행화면 gif

 

 

3. 데이터를 기반으로 리스트 뷰 만들기 | ListView.builder

ListView의 builder를 이용하면, 데이터의 갯수 만큼 loop를 돌면서 Widget을 만들어 준다

 

3.1 소스코드

import 'package:flutter/material.dart'; 

final List<String> entries = <String>['A', 'B', 'C'];
final List<int> colorCodes = <int>[600, 500, 100];

void main(){
  runApp(
    MaterialApp( 
        home: ListView.builder(
          padding: const EdgeInsets.all(8.0),
          itemCount: entries.length,
          itemBuilder: (BuildContext context, int index) {
            return Container(
              height: 50,
              color: Colors.amber[colorCodes[index]],
              child: Center(child: Text('Entry ${entries[index]}')),
            );
          }
        )
      )
  );
} 

entries 배열의 갯수 만큼 itemBuilder가 동작된다. 

itemBuilder의 콜백 함수에는 context와 index가 들어있는데. 

이 index를 이용해서 데이터에 접근하고 Container Widget을 만들어서 반환해주고 있다

 

3.2 실행화면

실행화면 png. drawer는 기존과 같다.

 

 

 

4. 데이터 증가에 따른 갱신 되는 ListView 만들기

가만 생각하니 아득해 졌습니다... 왜냐하면 MVC 패턴에 너무 익숙해져 있어서..

데이터가 줄거나 증가했을때 ListView를 갱신시킬 생각을 하고 있었거든요

 

flutter는 Widget기반이고, 변하는 위젯은 statefulWidget 이라는것을 잊고 있었습니다

 

4.1 설계

거추장 스럽지 않게 일단은 제 수준으로 갱신을 해보도록 하겠습니다 

  1. Stateful Widget에 액션을 줍니다
  2. 액션으로 데이터가 생기고, 데이터를 배열에 추가 합니다
  3. State를 새로 바꾸기 위해 setState() 함수를 호출합니다
  4. StatefulWidget은 상태가 변화됨을 감지하고 build() 함수를 호출 합니다
  5. build()함수 내부엔 ListView.builder를 이용해서 데이터 배열을 ListView Widget으로 만들 수 있도록 합니다

4.2 화면 구성

DesignArea는 단순히 화면을 꾸미는 용도로 사용되었습니다

항상 새로운 데이터를 만들고 상태 변화를 주게 될 Action Area.

그 상태를 받아서 매번 새로 그리게 될 MyDisplay Area로 구성하였습니다

 

 

4.3 소스

flutter는 widget기반이기 때문에, 화면구성만 잘하면 금방 소스코드를 만들 수 있습니다

import 'package:flutter/material.dart'; 

void main(){
  runApp(
    MaterialApp( 
        home: Scaffold(
          appBar: AppBar(
            title: Text('Dynamic ListView')
          ),
          body:MyDisplay()
        )
      )
  );
} 

class MyDisplay extends StatefulWidget {
  
  @override
  State<StatefulWidget> createState() => MyListState();
}

class MyListState extends State<MyDisplay> {

  List<String> items = [];

  @override
  Widget build(BuildContext context) {
    
    return Column(children: <Widget>[
      RaisedButton(
        child: Text('Add'), 
        onPressed: () {
          items.add(DateTime.now().toIso8601String());
          setState((){});
        },
        textColor: Colors.white,
        color: Colors.lightGreen,
      ),
      Expanded(
        child: ListView.builder(
          itemCount: items.length,
          itemBuilder: (BuildContext context, int index){
            return Text(items[index]);
          }
        )
      )
    ]);
  }

}

상태가 변경되면 매번 새로 그리고 매번 새로운 객체가 생기나 싶지만, 우리는 createState()때 한번만 생성해 주는 것을 알 수 있습니다. 

상태가 RaisedButton을 누를때마다 새로 세팅되지만, 상태가 변경되는 것이지, 상태가 새로 생기는게 아니기 때문에 String리스트인 items가 데이터를 유지할 수 있습니다.

 

 

 

4.4 실행화면

Add 버튼을 눌러서 데이터를 추가한 gif

 

 

 

 

 

 

 

댓글