Flutter - 위젯 다루기 (Scaffold, Text, Column&Row, TextFiled, Button, appBar, Padding, Container, Image, SingleChildScrollView)

반응형

 

해당 포스팅의 전체 소스 코드가 포함된 프로젝트 파일은 깃허브에서 다운로드 가능합니다.

https://github.com/luvris2/flutter-example/tree/main/flutter_widget_test


Scaffold 위젯

  • MaterialApp의 디자인 레이아웃을 제공하는 위젯
  • 일반적으로 사용되는 많은 UI 구성 요소를 포함하는 컨테이너
    • 앱 바, 플로팅 작업 버튼, 하단 내비게이션 바 등 
  • 즉, 개발자가 UI 구성 요소를 추가 또는 제거하고 모양을 변경하거나 기능을 추가하는 작업을 할 수 있음
  • 하위 위젯
    • appBar
      • 화면 상단에 앱 바를 표시하는 하위 위젯
      • 일반적으로 제목과 선택적으로 일부 작업 또는 탐색 버튼을 포함 (글쓰기 버튼 등)
    • body
      • appBar 아래에 나타나는 화면의 메인 콘텐츠를 표시하는 위젯
      • 포시되는 위젯 : Text위젯, ListView위젯, Column&Row 위젯 등
    • floatingActionButton
      • 화면 우측 하단에 플로팅 액션 버튼을 표시하는 서브 위젯
      • 새 항목 추가, 새 작업 시작, GPS 현재 위치 보기 등 앱 작업에 사용
    • drawer
      • 화면 왼쪽에 스와이프하여 목록을 볼 수 있는 하위 위젯
      • 일반적으로 탐색 링크, 설정, 기타 콘텐츠가 포함
    • buttomNavigationBar
      • 화면 하단에 내비게이션 바를 표시하는 하위 위젯
      • 앱의 다른 섹션이나 화면을 나타내는 몇 가지 아이콘이 포함
home: Scaffold(
    // 코드 작성
),

<Scaffold 설명을 위한 예시 앱, 출처 스파르타코딩클럽>


Text 위젯

  • 텍스트를 보여줄 때 사용하는 위젯
  • 속성을 이용하여 텍스트의 모양을 바꿀 수 있음
  • 속성
    • style : 문자의 글꼴, 색상, 크기, 두께 등을 정의하는 TextStyle 개체
    • textAlign : 문자의 가로 정렬을 설정하는 TextAlign 유형의 열거형
    • textDirection : 문자의 방향, 왼쪽에서 오른쪽인지, 오른쪽에서 왼쪽인지 설정하는 TextDirection의 열거형
    • softWrap : 문자가 텍스트 위젯을 초과하는 경우 다음 줄로 줄 바꿈되어야 하는지 여부를 나타내는 부울 값
    • overflow : 문자가 텍스트 위젯을 초과하는 경우 텍스트를 처리하는 방법을 설정하는 TextOverflow 유형의 열거형
    • maxLines : 문자가 표시할 수 있는 최대 줄 수 지정, null로 설정하면 필요한 줄만큼 크기를 차지
    • textScaleFactor : 문자의 배율을 지정하는 부동 소수점 값, 1.5로 설정시 원래 크기의 150%로 표시
Text(
	// 코드 작성
),

 

  • 예시) 글씨가 30이고 볼드 효과가 들어간 빨간색 글씨로 'Hello World' 출력해보기
Text(
    'Hello, World!!!',
    style: TextStyle(
          fontSize: 30, // 폰트 크기
          fontWeight: FontWeight.bold, // 폰트 두께
          color: Color.fromRGBO(255, 0, 0, 1), // 폰트 색상(R,G,B,Opacity)
    ), // TextStyle
), // Text


Column&Row 위젯

  • Columns : 세로 열로 자식을 표시해주는 위젯
  • Row : 가로 행으로 자식을 표시해주는 위젯
  • 위젯을 서로 쌓고 정렬하는 데 사용
  • 속성
    • cildren : 자식으로 표시되는 위젯, 즉 행과 열 안에 표시되는 내용을 포함해주는 위젯
Column(
	// 코드 작성
),

 

  • 예시) 'Hello World' 아래에 새로운 열 추가하기
Column(
  children: [
    Center(
      child: Text(
        'Hello, World!!!',
        style: TextStyle(
          fontSize: 30, // 폰트 크기
          fontWeight: FontWeight.bold, // 폰트 두께
          color: Color.fromRGBO(255, 0, 0, 1), // 출력할 내용
        ), // TextStyle
      ), // Text
    ), // Center
    Text('Second Column'),
  ],
), // Column


TextField 위젯

  • 사용자가 텍스트를 입력할 수 있는 공간을 제공하는 위젯
    • 검색 창 및 회원가입, 로그인 등
  • 속성
    • decoration : 텍스트필드에 표시될 설명과 제목, 테두리를 설정하는데 사용하는 InputDecoration 개체
    • onChanged : 사용자가 텍스트필드에 텍스트를 입력하거나 변경할 때마다 실행되는 콜백 함수
    • keyboardType : 텍스트필드를 선택할 때 표시되는 키보드 유형을 설정하는 TextInputType 유형의 열거형
    • maxLines : 텍스트필드에 입력할 수 있는 최대 텍스트 줄 설정
    • maxLength : 텍스트필드에 입력할 수 있는 최대 문자 수 설정
    • obscureText : 암호 입력과 같이 텍스트를 가려야하는지 여부를 설정
    • style : 텍스트필드에 표시되는 텍스트의 스타일을 지정하는 TextStyle 개체
    • textAlign : 텍스트필드에서 텍스트의 가로를 정려하는 TextAlign 유형의 열거형
TextField(
    // obscureText: true = 입력한 텍스트를 별표로 표시
    decoration: InputDecoration(
	// 코드 작성
    // labelText: 텍스트필드 제목
    // hintText: 텍스트필드를 누를 경우 나올 설명
    ),
),

 

  • 예시) 위에서 추가한 'Second Column' 바로 밑에 사용자 입력 필드 두 개 추가하고 'abcd' 입력
    • 첫번째 : 텍스트를 입력할 텍스트 필드 (ID 입력)
    • 두번째 : 텍스트를 입력하면 별표로 바뀌어서 보이게하는 텍스트 필드 (비밀번호 입력)
Column(
  children: [
    Center(
      child: Text(
        'Hello, World!!!',
        style: TextStyle(
          fontSize: 30, // 폰트 크기
          fontWeight: FontWeight.bold, // 폰트 두께
          color: Color.fromRGBO(255, 0, 0, 1), // 출력할 내용
        ), // TextStyle
      ), // Text
    ), // Center
    TextField(
      decoration: InputDecoration(
        hintText: '입력한 글자는 그대로 보입니다.',
        labelText: '텍스트필드1',
      ), // InputDecoration
    ), // TextField
    TextField(
      obscureText: true,
      decoration: InputDecoration(
        hintText: '입력한 글자는 암호화 됩니다.',
        labelText: '텍스트필드2',
      ), // InputDecoration
    ), // TextField
  ],
), // Column


Button 위젯

  • 사용자 인터페이스에서 클릭 가능한 버튼을 제공하는 위젯
  • 속성
    • onPressed : 버튼을 눌렀을 때 실행되는 콜백 함수
    • child : 버튼 내부에 표시되는 위젯
  • 버튼의 종류
    • Elevated Button : 배경색이 채워진 볼록한 버튼
    • Text Button : 다양한 스타일로 사용자가 정의할 수 있는 텍스트가 있는 플랫 버튼
    • Outlined Button : 테두리와 투명한 배경이 있는 버튼
    • Icon Button : 아이콘으로 표시되는 버튼

ElevatedButton(
  onPressed: () {},
  child: Text('Elevated Button'),
),

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

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

IconButton(
  onPressed: () {},
  icon: Icon(Icons.add),
),

 

예시) 위의 Columns 위젯에 각각의 버튼 추가해보기

Column(
  children: [
    Center(
      child: Text(
        'Hello, World!!!',
        style: TextStyle(
          fontSize: 30, // 폰트 크기
          fontWeight: FontWeight.bold, // 폰트 두께
          color: Color.fromRGBO(255, 0, 0, 1), // 출력할 내용
        ), // TextStyle
      ), // Text
    ), // Center
    TextField(
      decoration: InputDecoration(
        hintText: '입력한 글자는 그대로 보입니다.',
        labelText: '텍스트필드1',
      ), // InputDecoration
    ), // TextField
    TextField(
      obscureText: true,
      decoration: InputDecoration(
        hintText: '입력한 글자는 암호화 됩니다.',
        labelText: '텍스트필드2',
      ), // InputDecoration
    ), // TextField
    ElevatedButton(
      onPressed: () {},
      child: Text('Elevated Button'),
    ), // ElevatedButton
    TextButton(
      onPressed: () {},
      child: Text('Text Button'),
    ), // TextButton
    OutlinedButton(
      onPressed: () {},
      child: Text('OutlinedButton'),
    ), // OutlinedButton
    IconButton(
      onPressed: () {},
      icon: Icon(Icons.add),
    ), // IconButton
  ],
), // Column


appBar 위젯

  • Scaffold의 상단 앱 바를 나타내는 위젯
  • 표준 앱 바 레이아웃을 제공
  • 제목, 선택적 작업을 하는 아이콘, 위젯을 포함
  • 속성
    • title : 앱 바 중앙에 표시할 문자 또는 위젯
    • backgroundColor : 앱 바의 배경색, 기본적으로 앱 테마의 기본 색상으로 설정
    • elevation : 앱 바 아래의 그림자 효과, 기본적으로 4.0으로 설정
    • centerTitle : 제목을 앱 바 중앙에 배치할지 여부를 결정, 부울 값으로 설정
  • 예시) 앱 바의 텍스트 중앙 정렬
home: Scaffold(
    appBar: AppBar(
      centerTitle: true, // 앱 상단바 텍스트 중앙 정렬
      title: Text('Hello World Example'), // 앱 상단바 설정
    ),
),


Padding 위젯

  • 자식 위젯 주위에 안쪽 여백을 제공하는 데 사용
  • 속성
    • padding
      • 자식 위젯에 적용할 안쪽 여백의 정도를 지정하는 EdgeInsets 개체
      • 4면에 동일한 안쪽 여백을 적용하거나 단일 값을 사용하여 각각의 4면에 별도의 값을 적용
        • EdgeInsets 개체 : 안쪽 여백의 정도를 지정하는 클래스, left right, top, bottom, all의 속성 이용
    • child : padding 위젯이 안쪽 여백을 적용하는 위젯
//전방위 모두 동일하게 적용
EdgeInsets.all(8)

//특정 방위만 적용
EdgeInsets.only(
  left: 8,
  right: 8,
)

//위아래 또는 좌우 적용
EdgeInsets.symmetric(
	vertical: 8,
	horizontal: 8,
)

<패딩 위젯이 하위 위젯을 감싸는 구조, 출처 스파르타코딩클럽>

 

  • Margin(바깥 여백)과 Padding(안쪽 여백), Border(테두리) 영역 확인
    • 사이즈는 예시를 위한 것일뿐 신경쓰지마세요.

 

  • 예시) 좌우에 50픽셀, 상단에 100픽셀의 안쪽 여백 만들기
body: Padding(
  padding: const EdgeInsets.only(
    left: 50,
    right: 50,
    top: 100,
  ), // EdgeInsets.only
  child: Columns(
  	// 하위 위젯 나열
    // 중략
  ), // Columns
), // Padding


Container 위젯

  • 다른 위젯을 데코레이션하고 배치하고 크기를 조정하는 방법등을 제공하는 위젯
  • 일반적으로 다른 위젯과 함께 그룹화하여 바깥쪽 여백, 안쪽 여백, 테두리 및 배경색과 같은 시각적 속성을 적용하는데 사용
  • 속성
    • alignment : 컨테이너 내 자식의 위치를 제어
    • padding : 컨테이너의 가장자리와 그 자식 사이의 안쪽 여백 정의
    • color : 컨테이너의 배경색을 설정
    • width : 컨테이너의 너비 설정, double.infinity : 부모의 사용가능한 모든 공간을 너비로 사용
    • height : 컨테이너의 높이 설정
    • decoration : 테두리, 배경 이미지 또는 기타 데코레이션을 컨테이너에 추가하는데 사용
  • 클래스
    • border : 위젯의 테두리를 정의하는데 사용, 종종 Container와 함께 사용하여 테두리를 추가
// 크기가 100x100인 컨테이너
Container(
  width: 100.0,
  height: 100.0,
  color: Colors.blue,
  child: Text('크기가 100x100인 컨테이너'),
), // Container

 

  • 예시) Elevated Button을 Container 위젯으로 감싸고 테두리와 가로 너비를 최대한 크게 조절해보기
    • 보더 클래스는 위젯이 아니기 때문에 이 포스팅에서는 따로 설명하지 않습니다.
Container(
    decoration: BoxDecoration(
      border: Border.all(
        color: Colors.black,
        width: 2.0,
        style: BorderStyle.solid,
      ), // Border.all
    ), // BoxDecoration
    width: double.infinity,
    child: ElevatedButton(
      onPressed: () {},
      child: Text('Elevated Button'),
    ), // ElevatedButton
), // Container
// 코드 생략


 

Image 위젯

  • 애플리케이션에 이미지를 표시하는 데 사용
  • 리소스, 네트워크, 메모리와 같은 다양한 소스에서 이미지를 로드할 수 있음
  • 속성
    • image
      • 표시할 이미지 소스
      • File, AssertImage, NetworkImage, MemoryImage, ImageProvider 객체로 표시
    • width, height
      • 이미지의 너비(width)와 높이(height)
      • 하나의 값만 지정된 경우 이미지는 해당 값에 비례하여 크기 조정
    • fit
      • 컨테이너에 맞게 이미지 크기를 조정
      • 옵션
        • BoxFit.contain : 전체 이미지가 상위 위젯 크기에 맞도록 이미지 크기 조정
        • BoxFit.cover : 상위 위젯에 전체를 덮으면서 이미지 크기 조정, 크기가 맞지 않으면 이미지의 일부 짤림 발생
        • BoxFit.fill : 부모 위젯을 완전히 채우도록 이미지 크기 조정, 가로 세로 비율 왜곡 발생 가능성 존재
        • BoxFit.fitHeight : 가로 세로 비율을 유지하면서 상위 위젯의 높이에 맞게 이미지 크기 조정, 이미지는 수평 중앙에 배치
        • BoxFit.fitWidth : 가로 세로 비율을 유지하면서 상위 위젯의 너비에 맞게 이미지 크기 조정, 이미지는 수직 중앙에 배치
        • BoxFit.none : 이미지 스케일링을 적용하지 않고 이미지 원래 크기로 표시
        • BoxFit.scaleDown : 상위 위젯에 맞도록 필요시 가로 세로 비율을 유지하면서 이미지 축소
    • alignment
      • 컨테이너 내 이미지를 정렬
      • 옵션
        • Alignment.topLeft : 컨테이너 왼쪽 상단 모서리 정렬
        • Alignment.topRight : 컨테이너 오른쪽 상단 모서리 정렬
        • Alignment.bottomLeft : 컨테이너 왼쪽 하단 모서리 정렬
        • Alignment.bottomRight : 컨테이너 오른쪽 하단 모서리 정렬
        • Alignment.center : 컨테이너 중앙 수평 수직 정렬
        • Alignment.topCenter : 수평으로는 컨테이너 중앙, 수직으로는 컨테이너 상단 정렬
        • Alignment.bottomCenter : 수평으로는 컨테이너 중앙, 수직으로는 컨테이너 하단 정렬
        • Alignment.centerLeft : 수평으로는 컨테이너 중앙, 수직으로는 컨테이너 왼쪽 정렬
        • Alignment.centerRight : 수평으로는 컨테이너 중앙, 수직으로는 컨테이너 오른쪽 정렬
    • repeat
      • 이미지가 컨테이너보다 작은 경우 컨테이너를 채우기 위해 이미지 반복 여부 설정
      • 옵션
        • ImageRepeat.noRepeat : 이미지 반복 없이 원래 크기로 한 번 표시
        • ImageRepeat.repeat : 이미지를 수평 수직으로 반복
        • ImageRepeat.repeatX : 이미지 가로로만 반복
//Image.asset()
//Image.file()
//Image.memory()
//Image.network()
/// Image.network('https://localhost:3000/my_image.png')

 

  • 예시) 최상단에 인터넷 URL로 이미지 넣기
    • 이미지는 원하는 이미지를 찾아서 넣기
Column(
    children: [
      Image.network(
          'https://static.wikia.nocookie.net/pokemon/images/a/aa/%EC%82%90_%EA%B3%B5%EC%8B%9D_%EC%9D%BC%EB%9F%AC%EC%8A%A4%ED%8A%B8.png/revision/latest/scale-to-width-down/200?cb=20170406071411&path-prefix=ko'),
	// 코드 생략
	],
) // Column


SingleChildScrollView 위젯

  • 사용 가능한 공간이 충분하지 않을 때 자식을 스크롤 할 수 있게 해주는 위젯
  • 컨테이너의 크기를 초과할 수 있는 위젯이 콘텐츠를 보기 위해 스크롤을 활성화하려는 경우에 사용
SingleChildScrollView(
  child: Column(
    children: [
      // 하위 위젯 코드 작성
    ],
  ),
)

 

SingleChildScrollView를 쓰는가?

 위에서 예시를 위해 제작한 앱을 살펴보면, 텍스트필드1을 선택시 키보드 입력 창이 출력되어 하위의 위젯들은 확인할 수 없는 상태가 됩니다. 이런 경우를 위해 'SingleChildScrollView' 위젯을 이용해서 Column, Row 등 그룹화 하는 위젯을 자식으로 두고 하위의 위젯들이 화면 크기를 초과하면 'SingleChildScrollView'을 통해 사용자가 스크롤하여 나머지 콘텐츠를 볼 수 있습니다.

(예시: 아래의 그림에서 키보드 입력으로 인한 화면 초과, 스크롤이 되지 않아 밑의 컨텐츠를 확인할 수 없는 상태)

 

  • 예시) 최상단에 'SingleChildScrollView' 위젯으로 감싸서 모든 하위 위젯들을 스크롤로 컨텐츠 확인해보기
    • 즉, 쉽게 말해서 최상위 부모 위젯 감싸기(포스팅에서는 Padding)
    • Tip : 최상위 부모는 코드의 제일 아래쪽을 보면 유추 가능함

 

  • 좌측의 노란 전구 - Wrap with widget

 

  • 생성된 위젯 이름을 SingleChildScrollView로 변경

home: Scaffold(
    appBar: AppBar(
      centerTitle: true, // 앱 상단바 텍스트 중앙 정렬
      title: Text('Hello World Example'), // 앱 상단바 설정
    ),
    body: SingleChildScrollView(
      child: Padding(
      	// 코드 생략
      ), // Padding
    , // SingleChildScrollView
), // Scaffold


전체 소스 코드

  • main.dart
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'hello_flutter', // 앱의 아이콘 이름
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true, // 앱 상단바 텍스트 중앙 정렬
          title: Text('Hello World Example'), // 앱 상단바 설정
        ),
        body: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.only(
              left: 50,
              right: 50,
              top: 100,
            ),
            child: Column(
              children: [
                Image.network(
                    'https://static.wikia.nocookie.net/pokemon/images/a/aa/%EC%82%90_%EA%B3%B5%EC%8B%9D_%EC%9D%BC%EB%9F%AC%EC%8A%A4%ED%8A%B8.png/revision/latest/scale-to-width-down/200?cb=20170406071411&path-prefix=ko'),
                Center(
                  child: Text(
                    'Hello, World!!!',
                    style: TextStyle(
                      fontSize: 30, // 폰트 크기
                      fontWeight: FontWeight.bold, // 폰트 두께
                      color: Color.fromRGBO(255, 0, 0, 1), // 출력할 내용
                    ),
                  ),
                ),
                TextField(
                  decoration: InputDecoration(
                    hintText: '입력한 글자는 그대로 보입니다.',
                    labelText: '텍스트필드1',
                  ),
                ),
                TextField(
                  obscureText: true,
                  decoration: InputDecoration(
                    hintText: '입력한 글자는 암호화 됩니다.',
                    labelText: '텍스트필드2',
                  ),
                ),
                Container(
                  decoration: BoxDecoration(
                    border: Border.all(
                      color: Colors.black,
                      width: 2.0,
                      style: BorderStyle.solid,
                    ),
                  ),
                  width: double.infinity,
                  child: ElevatedButton(
                    onPressed: () {},
                    child: Text('Elevated Button'),
                  ),
                ),
                TextButton(
                  onPressed: () {},
                  child: Text('Text Button'),
                ),
                OutlinedButton(
                  onPressed: () {},
                  child: Text('OutlinedButton'),
                ),
                IconButton(
                  onPressed: () {},
                  icon: Icon(Icons.add),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

참고

반응형