-
[Flutter] ์ฒ์ Flutter ์ ๋ฌธ์๋ผ๋ฉด ํ๋ฒ ๋ณด๋ฉด ์ข์ ๋จธํฐ๋ฆฌ์ผ ๊ตฌ์ฑ์์ ๊ธฐ๋ณธ์ฌํญ ๐๊ฐ๋ฐ/Flutter๐ฑ 2023. 8. 16. 20:26
์ต๊ทผ์ ๊ถ๊ธํ ๋ถ๋ถ์ด ์์๋๋ฐ ๋ฌผ์ด๋ณผ ๊ณณ์ด ์์ด์
์ฐพ๋ค๊ฐ Flutter์คํ ์ฑํ ๋ฐฉ์ด ์์ด์ ๋ค์ด๊ฐ์ ์ธ์ฌ๋ฅผ ํ๋๋ฐ..
[Me] -"์๋ ํ์ธ์:) ํ๋ฃจํฐ ๋ฐฐ์ด์ง 3๊ฐ์์ ๋ ๋ฌ์ต๋๋คใ ์ ๋ถํ๋๋ฆฝ๋๋ค."
๋ผ๊ณ ํ๋ค๊ฐ...
[๊ฐ] - ํ๋ฌ๋ฌ์?
[๋] - ํ๋ฌํฐ๋ณด๋จ ํ๋ฌํ ์ด..
[๋ค] - ํ๋ฃจํ ์?
[๋ผ] - ํ๋ฃจํฐ ํ๋๋ ํ๋ฃจ์ ๊ฑธ๋ฆฐ๊ฑด๊ฐ...
.
.
.
์๋ ๊ฒ 10๋ถ๋์ ๋ง์ฅ๋์ด ์์๋์๋ค๋.. ๐ฅฒ
Material Design๋?
์ฌ์ฉ์ ์ธํฐํ์ด์ค ๋์์ธ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ง์ํ๋ ์ ์ํ ๊ฐ์ด๋๋ผ์ธ, ๊ตฌ์ฑ์์ ๋ฐ ๋๊ตฌ ์์คํ .
์คํ ์์ค ์ฝ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ Material Design์ ๋์์ด๋์ ๊ฐ๋ฐ์ ๊ฐ์ ํ์ ์ ๊ฐ์ํํ๊ณ ํ์ด ์๋ฆ๋ค์ด ์ ํ์ ์ ์ํ๊ฒ ๊ตฌ์ถํ ์ ์๋๋ก ์ง์ํจ.
Material Flutter ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์ฑ๊ณผ ํ๋ซํผ ์ ๋ฐ์ ๊ฑธ์ณ ์ผ๊ด์ ์ธ ์ฌ์ฉ์ ํ๊ฒฝ์ ๋ง๋ค๊ธฐ ์ํด Material Design ๊ตฌ์ฑ์์ (์ค์ฌ์ MDC)์ ๋์์ธ์ ๊ตฌํํ๋ Flutter ์์ ฏ์ด ํฌํจ๋์ด ์์.
์์ํ๊ธฐ์ .
github์์ ์ผ๋ถ ์์ค ๋ค์ด ๐
git clone https://github.com/material-components/material-components-flutter-codelabs.git cd material-components-flutter-codelabs/mdc_100_series git checkout 101-starter
MDC-101 ๋ชฉํ : ๋ก๊ทธ์ธ ํ๋ฉด ๋ง๋ค๊ธฐ.
1. ์ด๋ฉ์ผ, ํจ์ค์๋ ์ ๋ ฅํ Textfield ๋ง๋ค๊ธฐ.
TextField( decoration: const InputDecoration( filled: true, //<- ๋ฐํ์ labelText: 'Username', ), ), // spacer const SizedBox(height: 12.0), // [Password] TextField( decoration: const InputDecoration( filled: true, labelText: 'Password', ), obscureText: true, ),
2.Textfield ์์ TextEditingController ๋ฃ๊ธฐ.
final _usernameController = TextEditingController(); final _passwordController = TextEditingController();
TextField( controller: _usernameController, decoration: const InputDecoration( filled: false, labelText: 'Username', ), ), const SizedBox(height: 12.0), TextField( controller: _passwordController, decoration: const InputDecoration( filled: true, labelText: 'Password', ), obscureText: true, )
โ๏ธTextfield์์ ฏ๊ณผ ์ธํธ๋ก ์์์ผ ํ ์ปจํธ๋กค๋ฌ!
TextEditingController
: ํธ์ง์ด ๊ฐ๋ฅํ TextField์ ์ ๋ ฅ๋ ๊ฐ์ ๊ฐ์ง๊ณ ์ค๊ฑฐ๋ ์ ๋ ฅ๋ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋ ์ฌ์ฉํ๋ ํด๋์ค
๊ธฐ๋ฅ
- clear() : ์ ๋ ฅํ ํ ์คํธ ๋ชจ๋ ์ญ์
editingController.clear();
- text : ํ์ฌ ์ ๋ ฅ๋ ๊ฐ ๊ฐ์ ธ์ค๊ธฐ (string)
editingController.text
- addListener: ์ํ๊ฐ ๋ณ๊ฒฝ์ด ๋ ๋๋ง๋ค ์๋ ค์ค.
editingController.addListener({function});
- dispose(): ๋ฆฌ์์ค ํด์ .
editingController.dispose();
๐กํจ๊ป ์์๋๋ฉด ์ข์ InputDecoration
InputDecoration์ ์ฌ์ฉํ๋ฉด Textfield ์์ ฏ์ ์ข ๋ ๋ค์ํ๊ฒ ์ฌ์ฉํ ์ ์์.
TextField( decoration: InputDecoration( labelText: 'Email', //<- ์ ๋ ฅ๋ ํ ์คํธ hintText: 'Enter your email', //<- ํํธ๋ก ๋ณด์ฌ์ฃผ๋ ํ ์คํธ labelStyle: TextStyle(color: Colors.redAccent), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(width: 1, color: Colors.redAccent), ), enabledBorder: OutlineInputBorder( //<- ํฌ์ปค์ค๋ซ์ ๋ borderRadius: BorderRadius.all(Radius.circular(10.0)), borderSide: BorderSide(width: 1, color: Colors.redAccent), ), border: OutlineInputBorder( //<- ๊ธฐ๋ณธ ๋ชจ์ borderRadius: BorderRadius.all(Radius.circular(10.0)), ), ), keyboardType: TextInputType.emailAddress,
3. ๋ฒํผ ์ถ๊ฐ
์ฌ์ฉ์๊ฐ ์ฑ์ ํตํด ์งํํ๊ธฐ๋ฅผ ๋ฐ๋๋๋ ElevatedButton, ์ฌ์ฉ์๊ฐ ํ์ง ์๊ธฐ๋ฅผ ๋ฐ๋ ๋๋ TextButton ์งํฅ.
(์ด์ธ์๋ OutlinedButton, FloatingActionButton IconButton ๋ฑ์ด ์์.)
๋ฒํผ์ ๋ชจ์ OverflowBar( alignment: MainAxisAlignment.end, // TODO: Add a beveled rectangular border to CANCEL (103) children: <Widget>[ // TODO: Add buttons (101) TextButton( child: const Text('CANCEL'), onPressed: () { // TODO: Clear the text fields (101) _usernameController.clear(); _passwordController.clear(); }, ), // TODO: Add an elevation to NEXT (103) // TODO: Add a beveled rectangular border to NEXT (103) ElevatedButton( child: const Text('NEXT'), onPressed: () { // TODO: Show the next page (101) Navigator.pop(context); }, ), ], )
๐กํจ๊ป ์์๋๋ฉด ์ข์ OverflowBar
: ์์๋ทฐ๋ฅผ ์ ๋ ฌ์ํด.
class MSOverflowBarRoute extends StatelessWidget { const MSOverflowBarRoute({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("MSOverflowBarRoute")), body: Column( children: [ OverflowBar( alignment: MainAxisAlignment.end, spacing: 20.0, textDirection: TextDirection.ltr, overflowSpacing: 20.0, overflowAlignment: OverflowBarAlignment.center, overflowDirection: VerticalDirection.down, clipBehavior: Clip.hardEdge, children: [ ElevatedButton(onPressed: () {}, child: Text("1XXXXXXXXXXX1")), ElevatedButton(onPressed: () {}, child: Text("1YYYYYYYYYYY1")), ], ), OverflowBar( alignment: MainAxisAlignment.spaceAround, spacing: 20.0, textDirection: TextDirection.rtl, overflowSpacing: 20.0, overflowAlignment: OverflowBarAlignment.center, overflowDirection: VerticalDirection.down, clipBehavior: Clip.hardEdge, children: [ ElevatedButton(onPressed: () {}, child: Text("2XXXXXXXXXXX2")), ElevatedButton(onPressed: () {}, child: Text("2YYYYYYYYYYY2")), ], ), OverflowBar( alignment: MainAxisAlignment.end, spacing: 20.0, textDirection: TextDirection.ltr, overflowSpacing: 10.0, overflowAlignment: OverflowBarAlignment.center, overflowDirection: VerticalDirection.down, clipBehavior: Clip.none, children: [ ElevatedButton(onPressed: () {}, child: Text("3XXXXXXXXXXX3")), ElevatedButton(onPressed: () {}, child: Text("3YYYYYYYYYYY3")), ElevatedButton(onPressed: () {}, child: Text("3ZZZZZZZZZZZ3")), ], ), OverflowBar( alignment: MainAxisAlignment.end, spacing: 20.0, textDirection: TextDirection.ltr, overflowSpacing: 10.0, overflowAlignment: OverflowBarAlignment.end, overflowDirection: VerticalDirection.up, clipBehavior: Clip.none, children: [ ElevatedButton(onPressed: () {}, child: Text("4XXXXXXXXXXX4")), ElevatedButton(onPressed: () {}, child: Text("4YYYYYYYYYYY4")), ElevatedButton(onPressed: () {}, child: Text("4ZZZZZZZZZZZ4")), ], ), ], ), ); } }
MDC-102 ๋ชฉํ : ์ํ ๋ชฉ๋ก ๋ฆฌ์คํธ ๋ง๋ค๊ธฐ
1. ์๋จ์ ์ฑ๋ฐ ์ถ๊ฐ
return Scaffold( // TODO: Add app bar (102) appBar: AppBar( title: Text('SHRINE'), // leading: IconButton( icon: const Icon( Icons.menu, semanticLabel: 'menu', ), onPressed: () { print('Menu button'); }, ), actions: <Widget>[ IconButton( icon: const Icon( Icons.search, semanticLabel: 'search', ), onPressed: () { print('Search button'); }, ), IconButton( icon: const Icon( Icons.tune, semanticLabel: 'filter', ), onPressed: () { print('Filter button'); }, ), ], ), body: Center( child: Text('You did it!'), ), // TODO: Set resizeToAvoidBottomInset (101) );
2. ์ํ ๋ชฉ๋ก ๋ง๋ค๊ธฐ (GridView ์ฌ์ฉ)
์ํ ๋ณด์ฌ์ค Card์ถ๊ฐ (์ํ ์ ๋ณด๋ ๋ค ์์ ํ์ผ ์์ ๋ค์ด ์์.)
List<Card> _buildGridCards(BuildContext context) { List<Product> products = ProductsRepository.loadProducts(Category.all); if (products.isEmpty) { return const <Card>[]; } final ThemeData theme = Theme.of(context); final NumberFormat formatter = NumberFormat.simpleCurrency(locale: Localizations.localeOf(context).toString()); return products.map((product) { return Card( clipBehavior: Clip.antiAlias, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ AspectRatio(aspectRatio: 18/11, child: Image.asset(product.assetName, package: product.assetPackage,),), Expanded(child: Padding( padding: const EdgeInsets.fromLTRB(16, 12, 16, 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text( product.name, style: theme.textTheme.titleLarge, maxLines: 1, ), const SizedBox(height: 8.0,), Text( formatter.format(product.price), style: theme.textTheme.titleSmall, ) ], ), )) ], ), ); } ).toList(); }
GridView์์ ์นด๋ ์ถ๊ฐ.
return Scaffold( // TODO: Add app bar (102) appBar: AppBar( title: Text('SHRINE'), leading: IconButton( icon: const Icon( Icons.menu, semanticLabel: 'menu', ), onPressed: () { print('Menu button'); }, ), actions: <Widget>[ IconButton( icon: const Icon( Icons.search, semanticLabel: 'search', ), onPressed: () { print('Search button'); }, ), IconButton( icon: const Icon( Icons.tune, semanticLabel: 'filter', ), onPressed: () { print('Filter button'); }, ), ], ), // TODO: Add a grid view (102) body: GridView.count(crossAxisCount: 2, padding: const EdgeInsets.all(16), childAspectRatio: 8.0/9.0, children: _buildGridCards(context),) // TODO: Set resizeToAvoidBottomInset (101) ); }
์ฌ๊ธฐ๊น์ง ํ๋ค๋ฉด ๊ธฐ๋ณธ์ ๋ค ์๋ ๊ฒ! ใ
[์ ์ฒด ์์ค]
: git@github.com:AlimE1789/materialComponents_101_102.git
๋ฐ์ํ'๊ฐ๋ฐ > Flutter๐ฑ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Flutter] Row๋ณด๋จ OverflowBar ๐ (0) 2023.08.17 [Flutter] ์ฑ ํ ์คํธ ํ๋ ๋ฐฉ๋ฒ (CodeLab) (0) 2023.08.08