23. 플러터 : 목록 보기 (무제한)

무제한 목록보기를 구현했다.
제목으로는 끝이 없다는 뜻으로 '무한리필'!
쩔지 않니, 우재야?

왼쪽은 앱 실행 후 첫 번째 화면, 오른쪽은 여러 페이지를 이동한 후의 화면.
출력 문자열은 양쪽에 3글자 영어 단어가 있고, 가운데는 항목 순서를 표시했지.
단어 10개 중에서 난수로 뽑았기 때문에 중복될 수 있고, 양쪽 그림 모두에서 중복된 패턴이 보인다. ㅎ



이번 코드에서 중요한 것은
여러 페이지를 넘어설 만큼 개수가 많을 때 ListTile 객체를 생성하는 방법이야.
3개만 생성한다면 한번에 생성할 수도 있지만
너무 많아지면 계속해서 나열할 수는 없기 때문에
반복적으로 필요할 때마다 생성할 수 있는 구성이 필요해.

ListView 클래스의 builder 생성자를 사용해서 리스트뷰 위젯을 만들면서
itemBuilder 옵션으로 ListTile 객체를 생성하는 방법을 알려주는 게 핵심 중의 핵심!


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

void main() => runApp(MaterialApp(home: MyApp()));

class MyApp extends StatelessWidget {
// 단어 목록으로부터 난수가 가리키는 위치의 단어를 보여주기 위한 변수 및 함수. 42는 seed.
final rand_gen = Random(42);
final words = ['ten', 'day', 'sky', 'fat', 'gym', 'run', 'ace', 'red', 'zen', 'sun'];

String randomWord() => words[rand_gen.nextInt(words.length)];
String capitalize(String s) => s[0].toUpperCase() + s.substring(1);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('무한리필')),
body: ListView.builder(
itemBuilder: (context, index) {
final first = capitalize(randomWord()); // 첫 글자가 대문자인 단어 생성
final second = capitalize(randomWord());
final disp_text = '$first $index $second';

return ListTile(
title: Center( // 항목 가운데 배치
child: Text(
'$first $index $second', // 원하는 형태로 조합
style: TextStyle( // 모든 단어를 같은 스타일로 처리
fontSize: 21,
fontWeight: FontWeight.bold,
),
),
),
onTap: () {
showDialog( // 초간단 경고창
context: context,
builder: (BuildContext ctx) => AlertDialog(title: Text(disp_text))
);
},
);
}
),
);
}
}


문자열에 포함된 단어 각각에 대해 다른 스타일을 적용하고 싶어졌어.
갑자기 그런 건 아니고
프로젝트를 하다 보면 그럴 경우가 많거든.
예전에는 문자열 3개를 Text 위젯으로 따로 만들어서 화면에서만 하나인 것처럼 했는데..
지금은 어렵지 않게 개별적인 스타일을 적용할 수 있게 라이브러리에서 지원을 하고 있어.

양쪽 영어 단어는 짙은 파랑, 가운데 순서는 빨강.
그리고 모든 단어는 폰트 크기를 키웠고 굵은 글씨로 수정했어.



앞쪽 코드에서 ListTile에 들어갈 title 옵션만 수정하면 돼.
TextSpan 위젯은 반드시 RichText 위젯의 자식으로 들어가야 하고
공통 스타일과 개별 스타일을 어떻게 적용하는지만 보면 돼.

참.. TextSpan 위젯 안에 TextSpan 위젯이 들어가는 거 중요하다!

title: Center(                          // 항목 가운데 배치
child: RichText(
text: TextSpan( // Text 확장
style: TextStyle( // 모든 자식에 대한 공통 스타일
fontSize: 21,
color: Colors.indigo,
fontWeight: FontWeight.bold,
),
children: [
TextSpan(text: first + ' '), // 1번 자식
TextSpan( // 2번 자식
text: index.toString(),
style: TextStyle( // 개별 스타일
color: Colors.red
),
),
TextSpan(text: ' ' + second), // 3번 자식
],
),
),
),