[Flutter] 플러터 위젯트리 익숙해지기

merci·2023년 3월 13일
0

Flutter

목록 보기
1/24
post-thumbnail
post-custom-banner

플러터 위젯의 트리 구조

하위 트리는 상위 트리 내부에 존재 해야한다.

MaterialApp

전체는 MaterialApp 내부에 존재 해야한다.

import 'package:flutter/material.dart';
import 'package:flutter_receipe/pages/recipe_page.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // 화면에 디버그 제거
      theme: ThemeData(
        fontFamily: "PatuaOne"
      ),
      home: RecipePage(), // 클래스 분리
    );
  }
}

Scaffold

MaterialApp 하위에 Scaffold 를 생성 ( = 페이지 )

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class RecipePage extends StatelessWidget { // StatelessWidget - 상태없음(고정된 뷰)
  const RecipePage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _appBar(), // 위젯 분리 / dart 에서 '_'는 private을 뜻함
      body: Padding( // 패딩을 주기 위해 위젯으로 감싼다.
        padding: const EdgeInsets.symmetric(horizontal: 16.0), // symmetric 대칭
        child: ListView( // ListView - 스크롤 가능
          children: [
            _title('Recipes'),
            _menus(), // 위젯 분리 ( ctrl + alt + m 키 사용)
            _listItem(imageName: "burger", title: "Made coffee", des: "커피 설명중입니다 아이스 아메리카노"),
            _listItem(imageName: "coffee", title: "Made Burger", des: "햄버거 만드는 설명입니다. 불고기 버거"),
            _listItem(imageName: "pizza", title: "Made Pizza", des: "피자 만드는 설명입니다. 파인애플 피자"),
          ],
        ),
      ),
    );
  }

원래 있는 위젯(ListView)을 Padding으로 감싸게 되면 child로 자식 위젯이 된다.

ScaffoldAppBar, Drawer, BottomNavigationBar, FloatingActionButton 같은 하위 위젯을 가진다.

AppBar

  AppBar _appBar() {
    return AppBar(
      backgroundColor: Colors.white, // 이 방식 보다 테마로 작성하는것이 좋다
      actions: [
        IconButton(
            onPressed: (){
              print("클릭됨");
            },
            icon: Icon(CupertinoIcons.search),
            color: Colors.black),
        SizedBox(width: 15), // 컴포넌트 사이 여백을 줄때 간단히 사용
        Icon(CupertinoIcons.heart, color: Colors.redAccent),
        SizedBox(width: 15,)
      ],
    );
  }
}

위 코드로 만든 AppBar

Scaffold의 body

  Widget _title(String text, {double tp = 20.0}) // 디폴트 값 20, 값을 바꿀 수 있다.
  => Padding( // 람다 표현식으로 타이틀 리턴
    padding:  EdgeInsets.only(top: tp ), // 원래 있던 const를 제거 동적으로 패딩 변환
    child: Text(text,style: TextStyle(fontSize: 30),),
  );
  Widget _menus() {
    return Padding(
      padding: const EdgeInsets.only(top: 20.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 가로 방향
            children: [
              _menu(icon: Icons.food_bank, des: "All"),
              _menu(icon: Icons.emoji_food_beverage, des: "Burger"),
              _menu(icon: Icons.fastfood, des: "Coffee"),
              _menu(icon: Icons.local_pizza, des: "Pizza"),
            ],
          ),
    );
  }

RowColumn은 자식 요소들을 가진다 => children

  Widget _menu({required var icon, required String des}) { 
  	// 컨테이너를 위젯타입으로 바꿔 놓으면 padding 같은 옵션 줄때 안 터짐
    return Container( 
      width: 60,
      height: 80,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25),
          border: Border.all(color: Colors.black87),
        ),
              child: Column(
              mainAxisAlignment: MainAxisAlignment.center, // 세로 방향
                children: [
                  Icon(icon, color: Colors.redAccent, size: 30),
                  Text(des)
                ],
              ),
            );
  }

Container는 크기를 정하지 않으면 최대한 크게 잡힌다.
decoration: BoxDecoration() 옵션으로 컨테이너의 모양을 잡을 수 있다.

여기 까지의 코드로 만들면

  Widget _listItem({required String imageName, required String title, required String des}) {
    return Padding(
      padding: const EdgeInsets.only(top: 30.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          ClipRRect(  
            borderRadius: BorderRadius.circular(15),
            child: AspectRatio(
                aspectRatio: 9/5 ,
                child: Image.asset("assets/images/${imageName}.jpeg",
                    fit: BoxFit.cover)
            ),
          ),
            Text(title, style: TextStyle(fontSize: 30),),
          Text(des),
        ],
      ),
    );
  }

required 는 다트문법인데 파라미터를 반드시 필요로 할 경우에 넣는다.

ClipRRect ClipRect 이름이 비슷해서 헷갈렸는데 차이는
ClipRRect 는 사각형모양의 UI를 둥글게 깍을때 사용한다.
ClipRect 는 사각형내부를 잘라내는데 사용한다. - 특정영역 제거

AspectRatio는 지정한 비율로 이미지를 표현할때 주로 사용한다.

위 코드로 만들면

profile
작은것부터
post-custom-banner

0개의 댓글