Flutter 기초. 위젯과 버튼에 대해 알아보자.
반응형

안녕하세요 😉

유유자적한 개발자 유로띠 입니다 😀

 

 

👏👏👏👏

 

 

이번 포스팅에서는

✅  컨테이너 위젯

✅  여백 스타일 위젯

✅  배치 및 공간 제어 위젯

✅  이미지 위젯

✅  동적 위젯

✅  버튼

에 대해서 알아보겠습니다

 

 

 

 

컨테이너 위젯


 

✅  단일 컨테이너 위젯

 

📍 Container

Container 안에는 다음과 같은 기능이 존재합니다.

body: Container(
        color: Colors.yellow,
        alignment: Alignment.center,
        margin: const EdgeInsets.symmetric(
          horizontal: 100, 
          vertical: 100
          ),
		padding: const EdgeInsets.symmetric(
          horizontal: 10, 
          vertical: 10
          ),
        child: const Text('hello world!!'),
      
      )

 

🟢  color

컨테이너의 색을 조정합니다.

color: Colors.yellow,

 

🟢  alignment

왼쪽, 오른쪽, 가운데 정렬 등 정렬을 조정합니다.

숫자를 이용하여 세밀한 정렬이 가능합니다.

alignment: const Alignment(0,0), // (0,0) = center
alignment: const Alignment.center,

 

🟢  width

가로길이를 조정합니다.

 

🟢  height

세로 길이를 조정합니다.

 

🟢  child

내용을 구성합니다.

child: const Text('hello world!!'),

 

🟢  margin

밖 쪽 여백이 생깁니다.

margin: const EdgeInsets.symmetric(
          horizontal: 100, 
          vertical: 100
          ),

 

🟢  padding

안쪽 여백이 생깁니다.

padding: const EdgeInsets.symmetric(
          horizontal: 10, 
          vertical: 10
          ),

 

 

 

Container에서 width, height만 사용하면 sizedBox를 사용하면 됩니다.

 

 

📍 SizedBox

간단하게 child의 width, height 사이즈를 조절합니다.

body: const SizedBox(
        width: 200,
        height: 200,
        child: Text('hello world!'),
    )

 

📍 Center

중앙 정렬된 컨테이너를 생성하려면 다음처럼 작성하면 됩니다.

body: const Center(
         child: Text('hello world!'),
      )

 

 

 

✅  복수 컨테이너 위젯

 

📍 Column

컨테이너를 여러 개 생성할 때 세로축으로 정렬합니다.

 

MainAxisAlignment는 Column이며, crossAxisAlignment는 Row입니다.

 

body: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
    Container(
        color: Colors.yellow,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('1'),

      ),
      Container(
        color: Colors.red,
        alignment: Alignment.center,
        width: 70,
        height: 70,
        child: const Text('2'),

      ),
      Container(
        color: Colors.blue,
        alignment: Alignment.center,
        width: 100,
        height: 100,
        child: const Text('3'),

      ),
    ],
  )

 

 

 

 

📍 Row

컨테이너를 여러개 생성할 때 가로축으로 정렬합니다.

 

body: Row(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
    Container(
        color: Colors.yellow,
        alignment: Alignment.center,
        width: 100,
        height: 40,
        child: const Text('1'),

      ),
      Container(
        color: Colors.red,
        alignment: Alignment.center,
        width: 100,
        height: 70,
        child: const Text('2'),

      ),
      Container(
        color: Colors.blue,
        alignment: Alignment.center,
        width: 100,
        height: 100,
        child: const Text('3'),

      ),
    ],
  )

 

 

 

 

 

 

 

📍 Wrap

overflow의 발생을 방지합니다.

그림처럼 3번째 박스가 크기가 커서 overflow일 때 자동으로 밀려 오른쪽에 위치됩니다.

direction를 통해 가로축(horizontal), 세로축 지정(vertical)

body: Wrap(
    direction: Axis.vertical, 
    children: [
    Container(
        color: Colors.yellow,
        alignment: Alignment.center,
        width: 40,
        height: 200,
        child: const Text('1'),

      ),
      Container(
        color: Colors.red,
        alignment: Alignment.center,
        width: 70,
        height: 200,
        child: const Text('2'),

      ),
      Container(
        color: Colors.blue,
        alignment: Alignment.center,
        width: 100,
        height: 200,
        child: const Text('3'),

      ),

 

 

 

여백 스타일 위젯


 

✅  padding

padding은 컨테이너가 존재합니다.

 

📍 EdgeInsetsGeometry Type

//여백 제거
margin: EdgeInsets.zero

// left, top, right, bottom  동일한 여백을 주고 싶을 때
margin: EdgeInsets.all(40),

//left, top, right, bottom 설정
margin: EdgeInsets.fromTRB(10, 20, 50, 100),

//특정 위치(left, top, right, bottom)에만 여백을 주고 싶을 때
margin: EdgeInsets.only(bottom: 100),

//가로, 세로 별로 여백을 주고 싶을 때
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),

 

 

 

 

배치 및 공간 제어 위젯


 

 

✅  Align

정렬을 조정할 때 사용합니다.

body: Alin(
	alignment: Alignment.center,
),

 

 

✅  Spacer

특정 위치에 여백을 설정할 때 사용한다.

flex를 이용하여 공백의 크기를 설정할 수 있다.

1번 박스2번 박스 사이에 Spacer의 flex 값 1을 주었고 2번 박스3번 박스 사이에 Spacer의 flex 값 2를 주었습니다.

body: Row(
    children: [
    Container(
        color: Colors.yellow,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('1'),

      ),
      const Spacer(
        flex: 1,
      ),
      Container(
        color: Colors.red,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('2'),

      ),
      const Spacer(
        flex: 2,
      ),
      Container(
        color: Colors.blue,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('3'),

      ),
      Container(
        color: Colors.green,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('4'),

      ),
    ],
  )

 

 

 

✅  Expanded

나머지 영역 안에 내용을 작성할 때 사용한다.

body: Row(
    children: [
    Container(
        color: Colors.yellow,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('1'),

      ),
      const Spacer(),
      Container(
        color: Colors.red,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('2'),

      ),
      const Expanded(
        child: Text('값을 입력할 때 expanded를 사용한다.'),
      ),
      Container(
        color: Colors.blue,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('3'),

      ),
      Container(
        color: Colors.green,
        alignment: Alignment.center,
        width: 40,
        height: 40,
        child: const Text('4'),

      ),
    ],
  )

 

 

 

 

이미지 위젯


 

 

✅  AssetImage

로컬 이미지를 표시할 때 사용합니다.

 

📍 pubspec.yaml

이미지를 첨부한 경로를 지정합니다.

단일 파일을 지정하여도 되고, 해당 폴더 하위의 모든 이미지를 가져올 수도 있습니다.

# 단일 이미지 파일
assets:
    - assets/images/image.jpg

# images 하위 폴더의 이미지 파일 전부
assets:
    - assets/images/

 

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: [ 
          Image.asset('assets/images/image1.JPG'),
          Image.asset('assets/images/image2.JPG'),
        ],
      ),
    );
  }

 

 

✅  NetworkImage

네트워크를 통한 이미지를 가져올 때 사용합니다.

플러터가 이미지 파일을 다운로드해서 캐시에 저장하고 화면에 출력합니다.

asset 이미지 방식보다 로딩이 느리며, 인터넷 연결이 필요합니다.

Scaffold(
      appBar: AppBar(),
      body: Column(
        children: [ 
          Image.network('https://ww.namu.la/s/86c340753dc5e6e09e441a01a25d2f15dc4d6df1c59088aca212f69a9f2be855cfd9fa0d84281de2508da01e40ac2dbf1e9614b64fcbcfb62c22be931e9c97b083a56303b32b7c38ea4ba17a299e78da7ea1a6f0c2e17b632269c1a00c147a85'),
          Image.network(
            'http://file3.instiz.net/data/file3/2020/03/14/3/7/f/37f2fc88c1eabe693f6b03c103d21855.gif',
            fit: BoxFit.fitWidth,
            width: 300,
            height: 300,
          ),
        ],
      ),
    );

 

 

 

아래의 코드처럼 사용 할 수도 있습니다. 

Image(
	image: AssetImage('assets/images/image1.JPG'),
)

Image(
	image: NetworkImage(
    	'http://file3.instiz.net/data/file3/2020/03/14/3/7/f/37f2fc88c1eabe693f6b03c103d21855.gif'
        ),
)

 

 

 

✅  File

외부 폴더나 갤러리에 있는 이미지를 가져올 때는 File을 사용합니다.

Image.file(file),

 

 

✅  공통 속성

위에 3가지 이미지 위젯은 width, height, BoxFit이라는 공통 속성을 가지고 있습니다.

width, heigth는 기본적인 것이라 아실 테고 BoxFit에 대해서 알아보겠습니다.

 

📍 fill

사이즈에 맞춰 비율을 왜곡하여 이미지를 변형해 채웁니다.

 

📍 contain (default)

이미지가 잘리지 않고 정해진 사이즈 안에서 비율이 변하지 않고 그려집니다.

 

📍 cover

이미지 비율은 유지한 채, 사이즈 벗어나면 이미지가 잘린 채 출력됩니다.

 

📍 fitWidth

width(너비) 사이즈에 맞춰 채워서 그립니다.

 

📍 fitHeight

height(높이) 사이즈에 맞춰 채워서 그립니다.

 

📍 none

원본 이미지 표시 경우에 따라 이미지 잘릴 수 있습니다.

 

📍 scaleDown

전체 이미지가 나올 수 있게 이미지 크기를 조절해서 기본값으로 가운데 맞춤으로 출력합니다.

 

 

💡 참고

 

BoxFit enum - painting library - Dart API

How a box should be inscribed into another box. See also: applyBoxFit, which applies the sizing semantics of these values (though not the alignment semantics). Constants contain → const BoxFit As large as possible while still containing the source entire

api.flutter.dev

 

 

 

 

동적 위젯


 

 

✅  stateful widget

값에 따라 화면에 반영할 때에는 StatefulWidget을 사용합니다.

statelessWidget에서 StatefulWidget으로 변경하는 방법은 간단합니다.

Convert to StatefulWidget를 선택하여 기존 코드를 변경할 수 있습니다.

 

 

 

 

버튼 클릭 시 숫자가 올라가는 카운팅 앱을 만들어 봅시다.

 

import 'package:flutter/material.dart';

class LottsHomePage extends StatefulWidget {
  LottsHomePage({ Key? key }) : super(key: key);

  @override
  State<LottsHomePage> createState() => _LottsHomePageState();
}

class _LottsHomePageState extends State<LottsHomePage> {
  
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Lotts Home Page')),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: (){
              //build를 다시 호출하여 다시 그린다.
              setState(() {
                count++;
              });
              print(count);
            }, 
            onLongPress: (){
              setState(() {
                count = 0;
              });
            },
            style: ElevatedButton.styleFrom(
              primary: Colors.orange,
              onPrimary: Colors.black,
            ),
            child: const Text('plus'),
          ),
          Center(
              child: Text('$count'),
            )
        ],
      )
      
    );
  }
}

 

int count = 0;으로 초기화해줍니다.

setState(() {});를 사용하면 build를 다시 실행하여 새롭게 그립니다.

화면에 변경된 정보를 확인할 수 있습니다.

 

 

버튼


 

✅  ElevatedButton
✅  OutlineButton
✅  TextButton

3개의 버튼은 생성자 형태가 동일하기 때문에 한 번에 설명드리겠습니다.

body: Column(
    children: [
      ElevatedButton(
        onPressed: (){
          print('ElevatedButton - onPressed');
        }, 
        onLongPress: (){
          print('ElevatedButton - onLongPress');
        },
        // button 스타일은 여기서 작성한다.
        style: ElevatedButton.styleFrom(
          primary: Colors.orange,
          onPrimary: Colors.black,
        ),
        child: const Text('ElevatedButton')
      ),

      OutlinedButton(
        onPressed: (){}, 
        child: const Text('OutlinedButton')
      ),

      TextButton(
        onPressed: (){}, 
        child: const Text('TextButton')
      ),

      GestureDetector(
        onTap: (){}, 
        child: const Text('GestureDetector')
      ),
    ],
  )

 

 

📍 onPressed

버튼 클릭 시 발생하는 이벤트입니다.

 

📍 onLongPress

버튼을 길게 클릭 시 발생하는 이벤트입니다.

 

📍 style

버튼의 스타일을 관리합니다.

 

 

✅  GestureDetector

클릭 시 이벤트를 가져가기 위한 버튼입니다.

주황색 화면을 클릭하면 이벤트가 발생합니다.

 

body: Column(
    children: [
      GestureDetector(
        onTap: (){
          print('GestureDetector');
        }, 
        child: Container(
          color: Colors.orange,
          height: 100,
        )
      ),
    ],
  )

 

 

✅  FloatingActionButton

다른 버튼과 달리 Scaffold 안에 floatingActionButton이 존재합니다.

오른쪽 하단에 동그라미 버튼이 생성됩니다.

 

Scaffold(
      appBar: AppBar(
      title: const Text('Lotts Home Page')),
      floatingActionButton: 
      FloatingActionButton(
        onPressed: (){},
        child: const Icon(
          Icons.plus_one,
          color: Colors.white,
        ),
      ),
    );

📍 onPressed

버튼 클릭 시 발생하는 이벤트입니다.

 

📍 Icon

다양한 아이콘을 사용할 수 있습니다.

 

 

 

 

 

이상

flutter 기본

위젯과 버튼에 대해 알아보았습니다.

 

 

반응형