Flutter - 완전 기초 ②: 무한 스크롤 ListView 화면 만들기
플러터 코드랩을 이어서 무한 스크롤 ListView를 만들어보자
Ex) 무한 스크롤 ListView
이제 ListView를 생성해서, 스크롤하면 무한하게 계속 랜덤 단어 짝을 만드는 화면을 생성해 보자
State 수정
class RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = const TextStyle(fontSize: 18.0);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
),
body: _buildSuggestions(),
);
}
}
final 변수로 단어 짝을 담을 _suggestions
배열과, TextStyle인 _biggerFont
를 추가한다.
build()
에서 원래는 그냥 Text()를 반환했었는데, 이번에는 Scaffold 자체를 return 해주기로 한다.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Temp',
home: RandomWords(),
);
}
}
따라서 MyApp 부분도 이렇게 home 자체를 RandomWords()
스테이트로 대체한다.
그럼 이제 RandomWordsState의 body가 될 _buildSuggestions()
를 보자. 당연하지만 RandomWordsState 클래스 안에 정의한다
Widget _buildSuggestions() {
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i) {
if (i.isOdd) return Divider();
final index = i ~/ 2;
if (index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
});
}
ListView.builder()
로 ListView를 생성해서 return한다.
padding
: EdgeInsets.all()
을 썼는데, 전체 여백을 지정하는 옵션이다. 상하좌우에 16.0의 여백을 준다. 만약 특정 부분만 하려면 EdgeInsets.only(left: 10.0)
과 같이 사용한다. 다른 것도 많이 있음
itemBuilder
: 아이템이 화면에 보여질 때 생성해낸다. 지금처럼 무한하게 만들거나 해서 아이템들을 미리 만들어 놓을 수 없을 때 쓰면 좋다.
+ itemCount
로 아이템 개수를 정할 수 있는데, 무한하게 늘어나게 할 것이므로 여기서는 사용하지 않는다.
.isOdd
로 홀수인지를 아는가 보다. 희한하넹
홀수일 때마다 Divider()
를 호출하는데, 이건 구분선으로, 각 항목을 구분하는 역할이다.
홀수마다 구분선이 있으므로, 0, 2, 4, …, 2n 번째마다 아이템이 들어가게 될 거다. 따라서 실제 아이템 index는 i ~/ 2
가 된다.
_suggestions
은 단어 짝 배열이다. index가 배열 크기보다 같거나 크면, 저장된 단어 짝을 다 썼다는 뜻이므로 10개를 더 생성해서 addAll()
로 _suggestions
에 추가해준다.
마지막으로, _buildRow()
로 타일을 return 한다.
Widget _buildRow(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
}
_buildRow()
는 그냥 ListTile을 return하는 간단한 함수다.
전체 코드
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Temp',
home: RandomWords(),
);
}
}
class RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = const TextStyle(fontSize: 18.0);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
),
body: _buildSuggestions(),
);
}
Widget _buildSuggestions() {
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i) {
if (i.isOdd) return Divider();
final 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,
),
);
}
}
class RandomWords extends StatefulWidget {
@override
RandomWordsState createState() => RandomWordsState();
}
실행 화면
잘 되는구나
Ex) ListView 구성 바꾸기
그럼 이제 조금 조작해 보자
리스트에 헤더도 달아줄 수도 있고, 10번째마다 다른 타일을 넣고 싶을 수도 있지
Widget _buildSuggestions() {
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, i) {
if( i == 0 ) return HeaderTile();
if( i % 2 == 1 ) return Divider();
final index = i ~/ 2;
if( index % 10 == 0 ) return TenthTile();
if( index >= _suggestions.length ){
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
});
}
_buildSuggestions()
함수에서, i가 0일 때 HeaderTile()
클래스 인스턴스를 리턴해서 헤더를 추가했고, index가 10번째일 때마다 TenthTile()
을 리턴하게 추가했다.
class TenthTile extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Container(
child: Image.network("https://..."),
);
}
}
Image.network("URL")
로 인터넷의 이미지 주소를 통해 불러올 수 있다. 이미지를 Container에 담아 return했다.
실행 화면
첫 헤더와 10번째 타일들이 잘 나온다. 이런 식으로 배리에이션을 주면 될 것 같다.
댓글남기기