[플러터] 10. 프로필과 GridView Builder

KangHo Lee's avatar
Dec 24, 2024
[플러터] 10. 프로필과 GridView Builder

원하는 화면

notion image

1. 화면 상단

return Scaffold( endDrawer: Container( // side bar 내용을 레이어로 하나 더 올리는 것 width: 200, color: Colors.yellow, ), appBar: AppBar( leading: Icon(Icons.arrow_back_ios), title: Text("Profile"), centerTitle: true, ), body: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 100, height: 100, child: CircleAvatar( backgroundImage: AssetImage("assets/avatar.png"), ), ), Column( children: [ Text("HelloWorld"), Text("Programer"), ], ), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ ElevatedButton(onPressed: () {}, child: Text("버튼1")), OutlinedButton(onPressed: () {}, child: Text("버튼2")), TextButton( onPressed: () {}, child: Text("버튼3"), style: TextButton.styleFrom( backgroundColor: Colors.blueAccent, foregroundColor: Colors.white, minimumSize: Size(200, 40), ), ), ], ),
  • endDrawer
    • 우측에 나오는 사이드 드로어 메뉴입니다.
    • 위치는 appbar 우측 action 부분에 있지만 앱 바 위에 얹지는 형식이라 appBar 밖에 써야 합니다.
  • SizedBox
    • width, height 속성이 없는 위젯의 크기를 설정하려면 SizedBox 위젯으로 감싸서 크기를 지정할 수 이씁니다.
  • CircleAvatar
    • 원형 아바타 위젯입니다.
    • backgroundImage는 AssetImage를 받을 수 있습니다.
  • Button 위젯 3가지
    • ElevatedButton
      • onPressed: 클릭 시 동작 설정
      • child: 버튼 텍스트 설정
    • OutlinedButton
      • 외곽선이 있는 버튼
    • TextButton
      • 일반 버튼입니다.
        • 💡
          style: TextButton.styleFrom
          → styleFrom으로 style 설정을 해줘야 버튼 내용이 바뀌어도 style이 유지됩니다.

2. TabBar

Expanded( child: DefaultTabController( initialIndex: 0, // 시작 인덱스 0 length: 2, child: Column( children: [ TabBar( tabs: <Widget>[ Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], // Widget ), // TabBar Expanded( child: TabBarView( children: <Widget>[ GridView.builder( physics: NeverScrollableScrollPhysics(), itemCount: 30, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 1, // x축 간격 mainAxisSpacing: 1, // y축 간격 ), itemBuilder: (context, index) { // index 0 부터 for 반복 실행, 빌더 써야 하는 이유 -> 통신에서 이미지 몇개 올지 모름 return Image.network( // 더미 사진 제공해주는 사이트 "https://picsum.photos/id/${200 + index}/200/300", fit: BoxFit.cover, ); }, ), // GridView.builder Center( child: Text("It's next tab here"), ), ], ), // TabBarView ), ], ), ), // DefaultTabController )

DefaultTabController

  • initialIndex
    • 최초로 켜져 있는 탭을 설정합니다.
  • length
    • 탭의 개수를 설정합니다.
  • TabBar와 TabBarView는 쌍으로 꼭 있어야 합니다.
  • TabBarView
    • children으로 위젯 리스트를 받습니다.
    • 높이 설정을 안 해줄 경우 “Horizontal viewport was given unbounded height.” 에러가 발생합니다.

GridView.builder

  • itemCount
    • 표시할 아이템 개수입니다.
  • gridDelegate
    • 그리드 레이아웃을 정의합니다.
    • SliverGridDelegateWithFixedCrossAxisCount → 그리드 레이아웃 설정
      • crossAxisCount: 1행에 배치할 아이템 개수
      • crossAxisSpacing: horizontal gap 설정
      • mainAxisSpacing: vertical gap 설정
  • itemBuilder
    • for 반복을 시행하면서 아이템을 동적으로 생성합니다.
  • physics: NeverScrollableScrollPhysics()
    • 이 속성은 그리드 내부의 스크롤을 비활성화합니다.
    • 즉, 그리드 뷰가 자체적으로 스크롤하지 않게 합니다.
    • 다른 스크롤 가능한 부모 위젯에 포함될 때 유용합니다.

3. 전체 코드

import 'package:flutter/material.dart'; void main() => runApp(const TabBarApp()); class TabBarApp extends StatelessWidget { const TabBarApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(useMaterial3: true), home: const TabBarExample(), ); } } class TabBarExample extends StatelessWidget { const TabBarExample({super.key}); @override Widget build(BuildContext context) { return Scaffold( endDrawer: Container( // side bar 내용을 레이어 하나 더 올리는 것 width: 200, color: Colors.yellow, ), appBar: AppBar( leading: Icon(Icons.arrow_back_ios), title: Text("Profile"), centerTitle: true, ), body: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 100, height: 100, child: CircleAvatar( backgroundImage: AssetImage("assets/avatar.png"), ), ), Column( children: [ Text("HelloWorld"), Text("Programer"), ], ), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ ElevatedButton(onPressed: () {}, child: Text("버튼1")), OutlinedButton(onPressed: () {}, child: Text("버튼2")), TextButton( onPressed: () {}, child: Text("버튼3"), style: TextButton.styleFrom( backgroundColor: Colors.blueAccent, foregroundColor: Colors.white, minimumSize: Size(200, 40), ), ), ], ), Expanded( child: DefaultTabController( initialIndex: 0, // 시작 인덱스 0 length: 2, child: Column( children: [ const TabBar( tabs: <Widget>[ Tab( icon: Icon(Icons.beach_access_sharp), ), // Tab Tab( icon: Icon(Icons.brightness_5_sharp), ), // Tab ], // Widget ), // TabBar Expanded( child: TabBarView( children: <Widget>[ GridView.builder( itemCount: 30, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 5, // x, y 축 간격 mainAxisSpacing: 1, ), itemBuilder: (context, index) { // index 0 부터 for 반복 실행, 빌더 써야 하는 이유 -> 통신에서 이미지 몇개 올지 모름 return Image.network( // 더미 사진 제공해주는 사이트 "https://picsum.photos/id/${200 + index}/200/300", fit: BoxFit.cover, ); }, ), // GridView.builder Center( child: Text("It's sunny here"), ), ], ), // TabBarView ), ], ), ), // DefaultTabController ), ], ), ); } }
Share article

devleekangho