실습: 위젯 컴포넌트화

Eungae's avatar
Dec 16, 2025
실습: 위젯 컴포넌트화
오늘의 핵심 학습 내용
  • 커스텀 위젯 만들기
  • 폰트 추가(yaml)
  • AppBar
  • Theme 적용
  • ListView
 
📖
component
명사 (구성) 요소, 부품
 
여기에서 flutter가 Dart 언어를 사용하는 강점이 폭발한다.
반복되는 위젯을 클래스로 구성해서 커스텀이 가능하다는 것!!
미친 커스텀!! 돌아버린 커스텀!!
클래스를 세팅할 줄만 안다면 무서울 게 없다.
그리고 클래스 내에서 바뀌는 것들은 파라미터로 받아주면 그만이다.
그건 생성자로 세팅하면 끝.
세상에.
다트 언어 공부할 때보다 오히려 플러터에서 실전으로 사용하니 훨씬 직관적이다.
 

컴포넌트화 하기

main.dart

import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_recipe/recipe_list_item.dart'; import 'package:flutter_recipe/recipe_menu.dart'; import 'package:flutter_recipe/recipe_title.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData(fontFamily: 'KBIZ'), home: RecipePage(), ); } } class RecipePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( actions: [ Icon(CupertinoIcons.search, size: 30), SizedBox(width: 15), Icon(CupertinoIcons.heart, size: 30, color: Colors.redAccent), SizedBox(width: 15), ], ), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: ListView( children: [ RecipeTitle(), RecipeMenu(), RecipeListItem( "assets/images/coffee.jpg", "맛있는 커피", "강릉은 커피의 도시, 그 중에서도 제일은 데자뷰 로스터리임. 여기 안 가봤으면 커피의 세계를 아직 다 안다고 할 수 없다. 여기서부터 새로운 지평선이 열림.", ), // for coffee RecipeListItem( "assets/images/burger.jpg", "존맛탱 버거", "햄버거 좀 치냐? 햄버거는 맥도날드지. 그치만 거기서 제일 맛있는 건 초코썬데이라는 사실.", ), // for burger RecipeListItem( "assets/images/pizza.jpg", "피자는 한물 갔음", "1인 가구 폭증으로 피자는 혼자 못 먹어, 피자의 시대가 가고 햄버거의 시대가 왔다. 혼자의 시대가 왔다. 그래도 가끔은 피자먹고 싶엉.", ), // for pizza ], ), ), ); } }
 

recipe_title.dart

import 'package:flutter/material.dart'; class RecipeTitle extends StatelessWidget { @override Widget build(BuildContext context) { return Text("레시피", style: TextStyle(fontSize: 30)); } }
 

recipe_menu.dart

import 'package:flutter/material.dart'; class RecipeMenu extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Row( children: [ menuItem(Icons.food_bank, "전체"), SizedBox(width: 25), menuItem(Icons.emoji_food_beverage, "음료"), SizedBox(width: 25), menuItem(Icons.fastfood, "버거"), SizedBox(width: 25), menuItem(Icons.local_pizza, "피자"), ], ), ); } Container menuItem(IconData icon, String text) { // menuItem은 Container (class)에 종속되는 메서드. return Container( width: 60, height: 80, decoration: BoxDecoration( border: Border.all(color: Colors.black12), borderRadius: BorderRadius.circular(30), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, size: 30, color: Colors.redAccent), SizedBox(height: 5), Text(text), ], ), ); } }
 

recipe_list_item.dart

import 'package:flutter/material.dart'; class RecipeListItem extends StatelessWidget { RecipeListItem(this.path, this.title, this.content); // 이게 생성자 -- 이걸로 인생이 편해짐 String path; String title; String content; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AspectRatio( aspectRatio: 2 / 1, child: ClipRRect( borderRadius: BorderRadius.circular(20), child: Image.asset(path, fit: BoxFit.cover), ), ), SizedBox(height: 8), Text(title, style: TextStyle(fontSize: 20)), SizedBox(height: 4), Text(content, style: TextStyle(fontSize: 12, color: Colors.black45)), ], ), ); } }
 
 

결과

notion image
 
 
아직 초보자인 나로서는 체력과 집중력을 많이 요하는 지금의 과정이 쉽지 만은 않지만,
어떤 결이랄까, 궁합으로 봤을 때는 나는 개발에 제법 잘 맞는 사람이다.
10년 일찍 왔어야 하는데 ㅋㅋㅋ
그치만 지금이라도 온 게 어디임. 10년 전에 왔으면 빌드맛에 빠져서 코드 깎는 노인이 되었을지도 모른다.
사업 흉내도 내보고, 빚 무서운 줄도 알고 - 이런 상태가 되었으니 단순히 코드만 짜는 게 아니라 세상을 볼 수 있게 된 거겠지.
 
그렇겠지 와따시…?
코드 공부 빨리 마치고 창업 아이템이나 다듬고 싶다 ㅋ
 
Share article

나새끼메이커