방명록
- [Flutter] "모두가 할 수 있는 플러터 UI 입문" - 프로필 앱 만들기2022년 02월 02일 00시 57분 58초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
"최주호, 정호준, & 정동진. (2021). 모두가 할 수 있는 플러터 UI 입문. 앤써북"으로 플러터 공부를 하고 있다. 이번 챕터에서는 Scaffold의 endDrawer 속성과 CircleAvatar, GridView, InkWell, TabBar, TabBarView 위젯 등을 다뤘다. components 폴더 아래에 dart 파일을 만든 후 main.dart에서 import하여 Scaffold의 body 영역에서 사용하는 방식은 앞서 만들었던 앱들과 다른 점이다. InkWell을 이용해 버튼을 만들고, TabBar와 TabBarView를 이용해 Tab을 구현하고, GridView.builder와 Image.network를 이용하여 특정 url주소의 이미지를 동적으로 처리하는 방법을 잘 기억하자!
// main.dart import 'package:flutter/material.dart'; import 'package:flutter_profile/components/profile_buttons.dart'; import 'package:flutter_profile/components/profile_count_info.dart'; import 'package:flutter_profile/components/profile_drawer.dart'; import 'package:flutter_profile/components/profile_header.dart'; import 'package:flutter_profile/components/profile_tab.dart'; import 'package:flutter_profile/theme.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, // 우측 상단 debug 표시 제거 theme: theme(), home: ProfilePage(), ); } } class ProfilePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( endDrawer: ProfileDrawer(), // AppBar 오른쪽에서 왼쪽으로 슬라이드 하는 Drawer, 만약 왼쪽에서 오른쪽으로 구현하고자 한다면 drawer를 사용한다. appBar: _buildProfileAppBar(), body: Column( children: [ SizedBox(height: 20), ProfileHeader(), SizedBox(height: 20), ProfileCountInfo(), SizedBox(height: 20), ProfileButtons(), Expanded(child: ProfileTab()), // 남아 있는 세로 공간을 모두 차지하게 한다. ], ), ); } AppBar _buildProfileAppBar() { return AppBar( leading: Icon(Icons.arrow_back_ios), title: Text( "Profile", style: TextStyle(color: Colors.grey[700]), ), centerTitle: true, ); } }
// theme.dart import 'package:flutter/material.dart'; ThemeData theme() { return ThemeData( primaryColor: Colors .white, // PrimaryColor는 브랜드의 아이덴티티를 나타내는 색. 기본값은 blue이다. ※AccentColor는 앱의 상호작용 요소에 사용하는 색이다. appBarTheme: AppBarTheme( backgroundColor: Colors.white, iconTheme: IconThemeData(color: Colors.blue), ), ); }
// components/profile_drawer.dart import 'package:flutter/material.dart'; class ProfileDrawer extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 200, height: double.infinity, // 해당 위젯이 차지할 수 있는 최대 범위로 확장할 때 사용 color: Colors.blue, ); } }
// components/profile_header.dart import 'package:flutter/material.dart'; class ProfileHeader extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ SizedBox(width: 20), _buildHeaderAvatar(), SizedBox(width: 20), _buildHeaderProfile(), ], ); } Widget _buildHeaderAvatar() { return SizedBox( width: 100, height: 100, // 이미지를 둥글게 만드는 법 3가지 // 1) Container 사용 decoration 속성 이용해 둥글게 만들고 Image 이용해 child로 추가 // 2) Image 위젯 만들고 ClipOver 위젯으로 감싸기 // 3) CircleAvatar 이용 child: CircleAvatar( backgroundImage: AssetImage("assets/avatar.jpg"), ), ); } Widget _buildHeaderProfile() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Sewol", style: TextStyle( fontSize: 25, fontWeight: FontWeight.w700, ), ), Text( "Full Stack Developer", style: TextStyle( fontSize: 20, ), ), Text( "it | insite", style: TextStyle( fontSize: 15, ), ) ], ); } }
// components/profile_count_info.dart import 'package:flutter/material.dart'; class ProfileCountInfo extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _buildInfo("77", "Posts"), _buildLine(), _buildInfo("55", "Likes"), _buildLine(), _buildInfo("33", "share"), ], ); } // 재사용 가능한 함수로 만든다. Widget _buildInfo(String count, String title) { return Column( children: [ Text( count, style: TextStyle(fontSize: 15), ), SizedBox(height: 2), Text( title, style: TextStyle(fontSize: 15), ), ], ); } Widget _buildLine() { return Container(width: 2, height: 60, color: Colors.blue); } }
// components/profile_buttons.dart import 'package:flutter/material.dart'; class ProfileButtons extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _buildFollowButton(), _buildMessageButton(), ], ); } Widget _buildFollowButton() { // InkWell은 모든 위젯을 버튼화 시킨다. 그 밖에 TextButton, ElevatedButton, OutlineButton으로 버튼을 만들 수 있다. return InkWell( onTap: () { print("Follow 버튼 클릭됨"); }, child: Container( alignment: Alignment.center, width: 150, height: 45, child: Text( "Follow", style: TextStyle(color: Colors.white), ), decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(10), ), ), ); } Widget _buildMessageButton() { return InkWell( onTap: () { print("Message 버튼 클릭됨"); }, child: Container( alignment: Alignment.center, // 내부 Text 가운데 정렬 width: 150, height: 45, child: Text( "Message", style: TextStyle(color: Colors.black), ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), // 모서리 둥글게 처리 border: Border.all(), // 테두리 선 적용 ), ), ); } }
// components/profile_tab.dart import 'package:flutter/material.dart'; // StatefulWidget은 변경 가능한 상태를 가진 위젯이다. class ProfileTab extends StatefulWidget { @override _ProfileTabState createState() => _ProfileTabState(); } class _ProfileTabState extends State<ProfileTab> // SingleTickerProviderStateMixin은 Mixin 타입으로 한 개의 애니메이션을 가진 위젯을 정의할 때 사용한다. with로 다중 상속 가능하다. with SingleTickerProviderStateMixin { TabController? _tabController; @override // initState는 StatefulWidget에만 존재하는 초기화를 위한 함수이다. 단 한번 실행된다. void initState() { super.initState(); _tabController = new TabController( length: 2, vsync: this); // vsync: this는 해당 위젯의 싱크를 SingleTickerProviderStateMixin에 맞춘다는 뜻이다. } @override Widget build(BuildContext context) { return Column( children: [ _buildTabBar(), Expanded(child: _buildTabBarView()), ], ); } Widget _buildTabBar() { return TabBar( controller: _tabController, tabs: [ Tab(icon: Icon(Icons.directions_car)), Tab(icon: Icon(Icons.directions_transit)), ], ); } Widget _buildTabBarView() { return TabBarView( controller: _tabController, children: [ // Container(color: Colors.green), // GridView.builder로 대체 // GridView는 수평방향이나 수직방향으로 고정 수의 위젯을 생성하고 반복해서 List를 출력해주는 위젯이다. // GridView에 들어오는 item 개수가 동적이라면 GridView.builder를 사용해야 한다. GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisSpacing: 10, crossAxisCount: 3, mainAxisSpacing: 10, ), itemCount: 42, itemBuilder: (context, index) { // Image.network를 사용하면 url의 이미지를 다운로드 한 뒤 화면에 표시할 수 있다. return Image.network( "https://picsum.photos/id/${index + 1}/200/200"); // https://picsum.photos 무료 이미지 사이트 }, ), Container(color: Colors.red), ], ); } }
728x90반응형'언어·프레임워크 > Flutter' 카테고리의 다른 글
[Flutter] 어느 날 갑자기 멀쩡했던 AVD도 고장 날 수 있다 | Failed to launch emulator: Error: Emulator didn’t connect within 60 seconds (0) 2022.02.06 [Flutter] "모두가 할 수 있는 플러터 UI 입문" - 로그인 앱 만들기 (0) 2022.02.03 [Flutter] "모두가 할 수 있는 플러터 UI 입문" - 레시피 앱 만들기 (0) 2022.02.01 [Flutter] "모두가 할 수 있는 플러터 UI 입문" - 스토어 앱 만들기 (0) 2022.02.01 [Flutter] "모두가 할 수 있는 플러터 UI 입문"과 함께한 Dart 기초 문법 요약정리 (0) 2022.01.31 다음글이 없습니다.이전글이 없습니다.댓글