[Flutter] 6. Flutter 프로젝트 만들기 (Profile)

편준민's avatar
May 27, 2025
[Flutter] 6. Flutter 프로젝트 만들기 (Profile)
💡
아래와 같은 인스타그램 프로필과 같은 앱 페이지를 만들어보겠다.
notion image

새로 배운 위젯

  • Drawer
  • CrossAxisAlignment
  • ElevatedButton
  • InkWell
  • TabBar
  • GridView
 

1️⃣ Appbar

💡
처음으로 Appbar에 위젯을 추가해보겠다. Appbar에 구조에서 맨 위쪽에 해당하는 3가지를 추가하였다. leading, title, actions 을 추가 하였는데, 이번 프로젝트 에서는 actions 말고 Drawer를 사용해 보겠다.

Drawer 위젯

Drawer 위젯은 앱에서 많이 사용되는 네비게이션바로 눌렀을 때 메뉴가 나오고 빈 공간을 눌렀을 때 네비게이션바가 들어가는 것이다. 해당 프로젝트에서 endDrawer를 사용한 이유는 endDrawer가 오른쪽에 배치 되기때문이다. Drawer를 사용할 경우에는 왼쪽에 배치된다.
class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( endDrawer: Container( width: 200, color: Colors.lightBlueAccent, ), appBar: AppBar( leading: Icon(Icons.arrow_back_ios), title: Center(child: Text("Profile")), ), body: Scaffold(), ); } }
notion image
notion image

2️⃣ Header

notion image
💡
CrossAxisAlignment는 이미지를 둥글게 만들어주는 위젯이다. 이미지의 크기를 조절 할 때에는 SizedBox로 감싸서 SizedBox의 크기를 변경하면 된다.
@override Widget build(BuildContext context) { return Row( children: [ SizedBox( height: 80, width: 80, child: CircleAvatar( backgroundImage: AssetImage("assets/person.png"), ), ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Ssar"), Text("Programer/Writer/Teacher"), Text("TherePrograming"), ], ), ], ); } }
notion image

3️⃣ info

notion image
💡
Container위젯을 활용하여 텍스트 2개가 하나가 되게 묶어서 재활용 가능한 위젯으로 만들었다.
class MInfo extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Column(children: [Text("50"), Text("Posts")]), Container(width: 2, height: 60, color: Colors.grey), Column(children: [Text("10"), Text("Likes")]), Container(width: 2, height: 60, color: Colors.grey), Column(children: [Text("3"), Text("Share")]), ], ); } }
notion image

4️⃣ Button 위젯들

notion image
💡
버튼을 만드는 방법은 대표적으로 4가지가 있다.
  • TextButton : 버튼 자체에 어떠한 디자인도 없음. Hover 효과만 있음.
  • ElevatedButton : 버튼 자체에 디자인이 있음. 그림자 효과로 인해 떠올라 있는 느낌을 줌
  • OutlinedButton : 버튼에 테두리 선에만 디자인이 있음.
  • InkWell : 모든 위젯을 버튼화 시켜줌
2가지 버튼을 ElevatedButtonInkWell을 사용하여 2가지 방법을 버튼을 만들어 보겠다.
ElevatedButton(onPressed: () {}, child: Text("Follow")),
notion image
ElevatedButton을 사용하여 디자인이 있는 버튼을 만들었다. 이후에 내가 완성 화면과 똑같이 커스터마이징을 해보겠다. 커스터마이징을 할 때 어떻게 해야할지 모르겠다면 flutter 공식 문서를 참고하면 된다. 아래 코드에서는 현재 fixedSize로 버튼의 크기를 강제로 주었지만, 이렇게 박스의 크기를 주게되면 화면이 커질 경우에 UI가 깨질 수 있으니 주의해야한다.
ElevatedButton( style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), backgroundColor: Colors.blue, fixedSize: Size(150, 45), ), onPressed: () {}, child: Text("Follow", style: TextStyle(color: Colors.white)), ),
notion image
Message 버튼은 직접 디자인을 하고 디자인한 박스를 InkWell위젯으로 감싸보겠다.
Container( width: 150, height: 45, child: Text("Message"), decoration: BoxDecoration( border: Border.all(color: Colors.black), borderRadius: BorderRadius.circular(10), ), alignment: Alignment(0, 0), ),
notion image
현재 디자인은 완성 되었지만, 버튼이 아니기 때문에 클릭은 되지 않는 상황이다. Container를 InkWell로 감싸보겠다.
InkWell( onTap: () {}, borderRadius: BorderRadius.circular(10), child: Container( width: 150, height: 45, child: Text("Message"), decoration: BoxDecoration( border: Border.all(color: Colors.black), borderRadius: BorderRadius.circular(10), ), alignment: Alignment(0, 0), ), )
버튼 이기 때문에 onTap이라는 속성을 이용하여 눌렸을 때 어떤 이벤트가 발동할 것인지를 정해줘야 버튼의 기능을 할 수 있다.

alignment 속성

alignment속성은 자식 위젯을 부모 위젯 내에서 어느 위치에 배치할지를 정하는 속성이다. 총 중앙을 포함하여 9가지 속성으로 위치를 정할 수 있고, 직접 위치를 정할 수도 있다.
커스텀 위치를 줄 때 에는 x, y 좌표로 위치를 정할 수 있는데 아래의 사진 같이, 0,0은 중앙을 의미하고 오른쪽은 수평방향 +1, 왼쪽은 수평방향 -1, 아래는 수직방향 +1, 는 수직방향 -1이다. (1, -1) 일 경우는 오른쪽 맨 위를 의미한다.
notion image
alignment: Alignment(1, -1)
notion image

5️⃣ TabBar

notion image
💡
TabBar같이 복잡한 기능을 처음에 사용할 경우에는 따로 프로젝트를 만들어서 TabBar의 사용법을 익히고 프로젝트에 익히는 것이 유용하다. 본 프로젝트에 바로 적용하게 되면 사용법을 익히는데에도 오래걸리고, 기존의 프로젝트도 망칠 수 있기 때문에 테스트를 해보고 사용하는 것을 추천한다.
Tabbar 샘플링
미리 샘플링 한 코드를 붙여넣기
class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( endDrawer: Container( width: 200, color: Colors.lightBlueAccent, ), appBar: _appbar(), body: Column( children: [ MHeader(), MInfo(), Row( children: [ MFollowButton(), MMessageButton(), ], ), Expanded( child: Column( children: [ DefaultTabController( length: 2, child: 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")), // Center 위젯 사용 시 가운데 정렬 ], ), ), ], ), ), ), ], ), ), ], ), ); }
notion image

6️⃣ GridView

notion image
💡
내가 원하는 행의 갯수만큼 정렬을 해주는 위젯이다. GridView또한 ListView와 같이 스크롤 이가능한 위젯이다. 첫번째 탭에서 해당 사진 처럼 나와야하기 때문에 TabBarView를 수정해 주어야한다.
class DetailTab extends StatelessWidget { @override Widget build(BuildContext context) { return Expanded( child: Column( children: [ DefaultTabController( length: 2, child: 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>[ GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, mainAxisSpacing: 2, crossAxisSpacing: 2, ), itemBuilder: (context, index) { return Image.network("https://picsum.photos/id/${index + 50}/200/200"); }, itemCount: 42, ), Center(child: Text("It's rainy here")), // Center 위젯 사용 시 가운데 정렬 ], ), ), ], ), ), ), ], ), ); } }
notion image

7️⃣ 최종 화면

notion image
Share article

YunSeolAn