무한으로 만들어지는 이름들을 선택하거나 해제하여 즐겨찾기에 포함할 수 있고, 앱 바의 오른쪽 상단에 목록 아이콘을 통해 즐겨찾기에 포함한 목록만을 볼 수 있습니다.
각 행에 좋아요 아이콘을 추가합니다. 다음으로 행을 누르면 즐겨찾기 기능이 되게합니다.
_saved
를 추가합니다. 이 Set 목록은 유저가 즐겨찾기한 단어 목록을 저장합니다. List를 사용하지 않고 Set을 사용하는 이유는 중복을 허용하지 않기 때문입니다.class RandomWordsState extends State<RandomWords> {
final List<WordPair> _suggestions = <WordPair>[];
final Set<WordPair> _saved = Set<WordPair>(); // 이 행을 추가합니다.
...
}
_buildRow
함수에서 단어가 이미 즐겨찾기에 저장되었는지 확인하는 Boolean 값을 추가합니다.Widget _buildRow(WordPair pair) {
final bool alreadySaved = _saved.contains(pair); // 이 줄을 추가합니다.
}
Widget _buildRow(WordPair pair) {
final bool alreadySaved = _saved.contains(pair);
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: Icon( // 여기서부터
alreadySaved: Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red: null,
), // 여기까지 추가합니다.
);
}
즐겨찾기 아이콘을 탭할 수 있는 기능을 추가합니다. 사용자가 목록에서 한 항목을 누르면 즐겨찾기 상태로 전환되고 해당 단어는 즐겨찾기 목록에 추가되거나 삭제됩니다.
이를 위해 _buildRow
기능을 수정합니다. 단어가 이미 즐겨찾기에 추가된 경우 단어가 즐겨찾기에서 제거됩니다. 한 항목을 누르면 setState()
를 사용하여 상태가 변경되었음을 프레임워크에 알립니다.
_buildRow
에 onTap
을 추가합니다.Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
onTap: () { // 여기서부터
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
}, // 여기까지 추가
);
}
TIP: Flutter에서 setState가 트리거되면
build
메서드가 재트리거되어 UI가 업데이트됩니다.
이 단계에서는 홈과 새 화면으로 이동하는 방법을 학습할 수 있습니다.
Flutter에서 Navigator는 앱 경로가 포함된 스택을 관리합니다. 경로를 네비게이터의 스택으로 쌓으면 디스플레이가 해당 경로로 업데이트됩니다. 네비게이터의 스택에서 빼면 이전 경로로 되돌아갑니다.
다음으로 RandomWordsState의 AppBar에 목록 아이콘을 추가합니다. 사용자가 목록 아이콘을 클릭하면 저장된 즐겨찾기가 포함된 새 화면이 네비게이터로 푸시됩니다.
class RandomWordsState extends State<RandomWords> {
...
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
actions: <Widget>[
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
...
}
_pushSaved()
함수를 RandomWordsState 클래스에 추가합니다.void _pushSaved() {
}
_pushSaved
가 비어있어 아무것도 동작하지 않습니다.다음으로 경로를 만들고 네비게이터의 스택으로 푸시합니다. 이 Action은 화면을 변경하여 새 경로를 표시합니다. 새 페이지의 내용은 MaterialPageRoute의 builder
속성에 익명함수로 작성됩니다.
Navigator.push
를 호출하여 Navigator의 스택으로 푸시합니다. IDE는 에러를 내지만 다음 섹션에서 수정할 것입니다.void _pushSaved() {
Navigator.of(context).push(
);
}
다음으로 MaterialPageRoute와 builder 메서드를 추가합니다. 우선 ListTile 행을 생성하는 코드를 추가합니다. diviedTiles()
메서드는 각 ListTile 사이에 수평 구분자 추가합니다.
void _pushSaved() {
Navigator.of(context).push(
MaterialPageRoute<void>( // 여기서부터
builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final List<Widget> divied = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList(); // 여기까지
}
),
);
}
builder 속성은 "Saved Suggestions" 라는 이름의 새 경로의 app bar를 포함한 Scaffold 를 리턴합니다.
void _pushSaved() {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final List<Widget> divied = ListTile
.divideTiles(
context: context,
tiles: tiles,
)
.toList();
return Scaffold( // 여기서부터
appBar: AppBar(
title: Text('Saved Suggestions'),
),
body: ListView(children: divieded),
); // 여기까지
}
)
)
}
ThemeData 클래스 를 구성하여 앱 테마를 쉽게 변경할 수 있습니다 . 이 앱은 현재 기본 테마를 사용하지만 앱의 기본 색상을 흰색으로 변경합니다.
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Startup Name Generator',
theme: ThemeData(
primaryColor: Colors.white,
),
home: RandomWords(),
)
}
}