1. Project 생성
- 기본 세팅
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
// 기본 구조 : 추후 작성하고 옮길 것
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Placeholder(),
);
}
}
기본 세팅 Live Template 생성 : Custom Snippet
- Settings → Live Template → Flutter에서 + 클릭 → New Live Template
- Abbreviation : 이름
- Description : 설명
- Template Text : 작성할 코드
- 아래쪽의 Define 혹은 Change 버튼을 눌러 적용할 코드의 범위 설정

- Template Text
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: $NAME$(),
);
}
}
class $NAME$ extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Placeholder(),
);
}
}
2. Tab Bar : Sampling
- 예제 코드를 통해 기능을 빠르게 숙지하고 본 프로젝트에 적용
- TabBar의 개수(length) = Tab 개수 = TabBarView 개수
- initialIndex : 시작할 탭 번호 (0부터 시작)
- Sampling을 통해 해당 기능의 Scale 파악을 쉽게 가능
import 'package:flutter/material.dart';
/// Flutter code sample for [TabBar].
void main() => runApp(const TabBarApp());
class TabBarApp extends StatelessWidget {
const TabBarApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: TabBarExample());
}
}
class TabBarExample extends StatelessWidget {
const TabBarExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TabBar Sample'),
),
body: DefaultTabController(
initialIndex: 0,
length: 2,
child: Column(
children: [
Container(
height: 300,
color: Colors.yellow,
),
Expanded(
child: Column(
children: [
TabBar(
tabs: <Widget>[
Tab(icon: Icon(Icons.cloud_outlined)),
Tab(icon: Icon(Icons.beach_access_sharp)),
],
),
Expanded(
child: TabBarView(
children: <Widget>[
Center(child: Text("It's cloudy here")),
Center(child: Text("It's rainy here")),
],
),
),
],
),
),
],
),
),
);
}
}
3. 코드 작성
- homepage.dart
- 메인 페이지를 작성하는 파일
- 여러 컴포넌트를 모아서 작성하는 페이지
Widgets
- Scaffold
- endDrawer : 끝에 메뉴를 추가하여 메뉴 화면을 열 수 있는 속성
- AppBar
- leading : 맨 처음 오는 아이콘
- Title : AppBar 제목
- centerTitle : 제목을 중앙에 오게 하는 속성
- iOS 기반일 경우 default가 중앙
import 'package:flutter/material.dart';
import 'package:flutter_prac_profile/component/profile_buttons.dart';
import 'package:flutter_prac_profile/component/profile_counter.dart';
import 'package:flutter_prac_profile/component/profile_drawer.dart';
import 'package:flutter_prac_profile/component/profile_header.dart';
import 'package:flutter_prac_profile/component/profile_tab.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
endDrawer: ProfileDrawer(),
appBar: _appBar(),
body: Column(
children: [
ProfileHeader(),
SizedBox(height: 20),
ProfileCounter(),
SizedBox(height: 20),
ProfileButtons(),
SizedBox(height: 20),
Expanded(
child: ProfileTab(),
),
],
),
);
}
AppBar _appBar() => AppBar(leading: Icon(Icons.arrow_back_ios_new), title: Text("Profile"), centerTitle: true);
}
- profile_drawer.dart
- Drawer 메뉴를 열어 나오는 화면을 작성하는 컴포넌트
import 'package:flutter/material.dart';
class ProfileDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(width: 300, color: Colors.lightBlueAccent);
}
}
- profile_header.dart
- 프로필 화면의 프로필 사진, 이름, 소개글 등을 작성하는 곳
- 프로필 사진을 둥글게 만들 수 있음
Widgets
- CircleAvatar : 배경 사진을 둥글게 만들 수 있는 위젯
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class ProfileHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
children: [
SizedBox(width: 20),
SizedBox(
width: 80,
height: 80,
child: CircleAvatar(
backgroundImage: AssetImage("assets/profile.png"),
),
),
SizedBox(width: 40),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Sxias", style: GoogleFonts.nanumGothic(fontSize: 30, fontWeight: FontWeight.w500)),
Text("Full Stack Programmer / Student", style: GoogleFonts.nanumGothic()),
Text("sxias.inblog.ai", style: GoogleFonts.nanumGothic()),
],
),
],
);
}
}
- profile_counter.dart
- 게시글, 좋아요, 공유 수를 표시하는 텍스트 및 구분 선을 모은 컴포넌트
- 구분 선은 SizedBox를 이용하여 제작
import 'package:flutter/material.dart';
class ProfileCounter extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [Text("50"), Text("Posts")],
),
Container(
width: 1,
height: 50,
color: Colors.lightBlueAccent,
),
Column(
children: [Text("10"), Text("Likes")],
),
Container(
width: 1,
height: 50,
color: Colors.lightBlueAccent,
),
Column(
children: [Text("3"), Text("Share")],
),
],
);
}
}
- profile_buttons.dart
- “Follow”, “Message” 버튼을 표시하는 컴포넌트
import 'package:flutter/material.dart';
import 'package:flutter_prac_profile/component/m_follow_button.dart';
import 'package:flutter_prac_profile/component/m_message_button.dart';
class ProfileButtons extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
MFollowButton(),
MMessageButton(),
],
);
}
}
- m_follow_button.dart
- InkWell과 Container를 이용하여, 해당 Container를 버튼으로 만드는 컴포넌트
- ElevatedButton 등 다른 버튼 클래스가 있지만, 가장 간편하게 버튼을 만들 수 있는 방법
Widgets
- InkWell : child를 버튼으로 만드는 위젯, onTap 속성에서 이벤트 등록 가능
- Align : 해당 item 내부를 정렬하는 위젯, 기본은 중앙 정렬
import 'package:flutter/material.dart';
class MFollowButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Container(
width: 150,
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(),
color: Colors.blueAccent,
),
child: Align(
child: Text(
"Follow",
style: TextStyle(color: Colors.white),
),
),
),
);
}
}
- m_message_button.dart
- InkWell과 Container를 이용하여, 해당 Container를 버튼으로 만드는 컴포넌트
import 'package:flutter/material.dart';
class MMessageButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Container(
width: 150,
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(),
color: Colors.white,
),
child: Align(
child: Text(
"Message",
),
),
),
);
}
}
- profile_tab.dart
- TabBar와 TabBarView를 묶어서 보여주는 TabController
- 부모의 높이를 정하고, 내부 item의 높이도 정해야 화면에 출력이 가능함
- Expanded 활용
- GridView의 Delegate 전략에 따라 다른 item 배치 가능
- 외부 이미지를 다운로드 받아 화면에 출력 가능
- builder를 사용하면 ViewResolver를 사용하여 메모리 사용량을 줄일 수 있음
- 화면에 필요한 item만을 불러옴
Widgets
- DefaultTabController : TabBar, TabBarView를 제어하는 컨트롤러
- length : Tab의 갯수
- initialIndex : 시작할 Tab의 번호
- TabBar : Tab 메뉴
- TabBarView : Tab을 선택했을 시에 보여줄 화면
- GridView.builder : 내부 Item을 그리드 배치할 수 있도록 만드는 Builder
- gridDelegate : 그리드 배치 전략 (고정갯수, 고정길이) - FixedCrossAxisCount
- crossAxisCount : 한 줄에 표시할 item 개수
- mainAxisSpacing : 메인 축 (세로축) Gap
- crossAxisSpacing : 보조 축 (가로축) Gap
- itemBuilder : 내부 아이템 - Expression 혹은 Statement로 표현 가능
- itemCount : 표시할 총 아이템 개수
- Image.network : url를 통해 받아올 수 있는 외부 이미지
import 'package:flutter/material.dart';
class ProfileTab extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
initialIndex: 0,
child: Expanded(
child: Column(
children: [
TabBar(
tabs: [
Tab(icon: Icon(Icons.notes)),
Tab(icon: Icon(Icons.play_arrow_rounded)),
],
),
Expanded(
child: TabBarView(
children: [
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 2,
mainAxisSpacing: 2,
),
itemBuilder: (context, index) {
print("index : $index");
return Image.network("https://picsum.photos/id/${index + 20}/200/200");
},
itemCount: 42,
),
Center(child: Text("test2")),
],
),
),
],
),
),
);
}
}
외부 이미지 사용
- picsum.photos/id/{id}/width/height 방식으로 요청 시 해당 사이즈에 맞는 사진을 전송해주는 사이트
Result

Share article