[Flutter #12] 리스트 뷰

2020. 11. 25. 07:35IT

리스트 뷰

지금까지 StatelessWidget을 사용해서 MyApp을 만들었고 그 안에 StatefulWidget을 이용해서 Text 위젯에 무작위 단어가 출력되는 코드를 만들었습니다. 이 코드를 이용해서 무작위 단어들을 리스트에 넣는 것을 구현해 보도록 하겠습니다.

 

     

 

만들었던 _RandomWordsState 클래스 내에 단어가 들어갈 변수를 만들어 줍니다. 그리고 폰트가 작아 잘 보이지 않아 폰트를 크게 만들기 위해서 폰트 스타일을 저장을 할 변수도 함께 클래스 맨 위에 선언을 해 줍니다.

 

class _RandomWordsState extends State<RandomWords> {

  final List<WordPair> _suggestions = <WordPair>[];

  final TextStyle _biggerFont = const TextStyle(fontSize: 18);

  @override

  Widget build(BuildContext context) {

 

 

  • final 변수

일반적으로 final이나 const로 변수를 정해 주고 값을 넣어주면 그 값은 변경을 할 수 없습니다. 이 원칙을 따르기 때문에 앞의 _suggestions와 _biggerFont의 값은 이후의 코드에서 변경을 할 수가 없습니다. 

단, _suggestions는 <WordPair>를 갖는 배열입니다. 배열에 대해서는 final로 정의를 해 줘도 예외적으로 배열 안의 값들을 변경할 수 있습니다.

 

다음은 _RandomWordsState 클래스 안에 ListView에 값들을 채워 넣을 _buildSuggestions라는 함수를 만들겠습니다.

 

  Widget _buildSuggestions() {

    return ListView.builder(

        padding: const EdgeInsets.all(16),

        itemBuilder: (BuildContext _context, int i) {

          if (i.isOdd) {

            return Divider();

          }

          final int index = i ~/ 2;

          if (index >= _suggestions.length) {

            _suggestions.addAll(generateWordPairs().take(10));

          }

          return _buildRow(_suggestions[index]);

        });

  }



ListView 클래스는 itemBuilder라는 속성을 이용해서 리스트에 값들을 채워 넣습니다. 그리고 여기에서는 i라는 변수가 사용이 되는데 이는 itemBuilder가 호출이 될 때마다 1씩 증가를 하며 0부터 시작합니다.

ListView에서 주의를 해야 할 것은 각 행마다 값들을 넣을 수 있는 것이 아니고 중간에 구분자(Divider)가 들어 있습니다.  

 

/*1*/ itemBuilder는 ListView가 그려질 때 자동으로 호출이 됩니다 

/*2*/ 0부터 i는 증가하는데 매번 호출 될 때마다 1씩 증가를 한다고 했습니다. 여기서는 홀수이면 Divider를 반환합니다. 

/*3*/ ~/2는 2로 나누었을 때의 몫을 계산합니다. 즉 i가 0, 1, 2, 3, 4, 5의 순서로 계속 호출이 될 때마다 index는 0, 0, 1, 1, 2, 2의 값을 갖게 됩니다. 다만 /*2*/에서 홀수일 경우 반환(return)이 되므로 이 코드까지는 오지 않습니다. 따라서 i는 0, 2, 4와 같이 짝수만 이 코드에 도달하게 되고 index 값은 0, 1, 2와 같이 1씩 증가하게 됩니다. 

/*4*/ 여기에서는 _suggestions가 끝에 도달했다면, 10개의 추가 공간을  _suggestions에 추가를 합니다. 

마지막 return 라인에서는 생성된 WordPair가 들어있는 _suggestions를 인덱스와 함께 반환을 합니다.

 

이번에는 _RandomWordsState 클래스 내에 _buildRow라는 함수를 만듭니다.

ListTile에 asPascalCase의 문자와 앞서서 선언해 준 _biggerFont를 사용하여 문자의 스타일을 지정해 줍니다.

 

  Widget _buildRow(WordPair pair) {

    return ListTile(

      title: Text(

        pair.asPascalCase,

        style: _biggerFont,

      ),

    );

  }



이번엔 _RandomWordsState 클래스 안의 build 클래스를 다음과 같이 변경을 해 줍니다.  Stateful 위젯의 build 함수이므로 상태가 바뀔때마다 호출됩니다. 따라서 그때마다 _buildSggestions 함수를 호출을 하게 됩니다. 기존에 MyApp에 있는 Scaffold가 이쪽으로 옮겨왔다고 보시면 되겠습니다.

 

따라서 MyApp의 build 함수내의 MaterialApp의 home 속성에서 RadomWord를 호출해 주고 기존의 코드를 삭제합니다. 

 

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

//    final wordPair = WordPair.random();

    return MaterialApp(

      title: "환영합니다",

      home: RandomWords(),

    );

  }

}



실행을 해 보시면 다음과 같은 결과를 얻을 수 있어야 합니다.

 

 

단 ListView에 보이는 WordPair들은 무작위로 생성된 것이므로 당연히 다르게 보일 것입니다.

 

최종 코드

지금까지 작성한 코드는 다음과 같습니다.

 

import 'package:flutter/material.dart';

import 'package:english_words/english_words.dart';

 

void main() => runApp(MyApp());

 

class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

//    final wordPair = WordPair.random();

    return MaterialApp(

      title: "환영합니다",

      home: RandomWords(),

    );

  }

}

 

class RandomWords extends StatefulWidget {

  @override

  _RandomWordsState createState() => _RandomWordsState();

}

 

class _RandomWordsState extends State<RandomWords> {

  final List<WordPair> _suggestions = <WordPair>[];

  final TextStyle _biggerFont = const TextStyle(fontSize: 18);

  @override

  Widget build(BuildContext context) {

    //final wordPair = WordPair.random();

    //return Text(wordPair.asPascalCase);

    return Scaffold(

      appBar: AppBar(

        title: Text('Startup Name Generator'),

      ),

      body: _buildSuggestions(),

    );

  }

 

  Widget _buildSuggestions() {

    return ListView.builder(

        padding: const EdgeInsets.all(16),

        itemBuilder: (BuildContext _context, int i) {

          if (i.isOdd) {

            return Divider();

          }

          final int index = i ~/ 2;

          if (index >= _suggestions.length) {

            _suggestions.addAll(generateWordPairs().take(10));

          }

          return _buildRow(_suggestions[index]);

        });

  }

 

  Widget _buildRow(WordPair pair) {

    return ListTile(

      title: Text(

        pair.asPascalCase,

        style: _biggerFont,

      ),

    );

  }

}

.

 

 

반응형