Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

nomad-programmer

[Programming/Flutter] 기본 위젯 (Widgets) 본문

Programming/Flutter

[Programming/Flutter] 기본 위젯 (Widgets)

scii 2020. 10. 7. 16:13

화면을 구성하는 컴포넌트를 위젯이라고 부른다. 화면을 구성하려면 다양한 위젯을 조합해야 하므로 가능하면 많은 위젯을 아는 것이 좋다.

https://flutter.dev/docs/development/ui/widgets

 

Widget catalog

A catalog of some of Flutter's rich set of widgets.

flutter.dev

앱을 만들려면 기본 위젯을 알아야 한다. UI를 위젯의 조합으로 구성하기 때문이다.

플러터는 머티리얼 디자인을 표준 디자인으로 채용하고, 필요에 따라서 iOS 쿠퍼티노 디자인도 사용할 수 있다. 그리고 다양한 화면 크기에 대응하는 방법을 제공한다.


화면 배치에 쓰는 기본 위젯

위젯 중에는 화면을 구성하고 배치하는 데 뼈대가 되는 것이 있다.

Container

아무것도 없는 위젯이다. 다양한 프로퍼티를 가지고 있기 때문에 사용하기에 따라서 다양한 응용이 가능하다. 자주 사용되는 위젯이다.

가로와 세로 길이, 색, 안쪽 여백(padding), 바깥쪽 여백(margin) 등의 설정이 가능하고 child 프로퍼티로 또 다른 위젯을 자식으로 가질 수 있다.

Container(
  color: Colors.red,
  width: 100,
  height: 100,
  padding: const EdgeInsets.all(5.0),
  margin: const EdgeInsets.all(5.0),
)

Column

수직 방향으로 위젯들을 나란히 배치하는 위젯이다. 레이아웃은 대부분 Column과 Row를 조합하여 만들기 때문에 매우 자주 사용한다.

children 프로퍼티에는 여러 위젯의 리스트를 지정할 수 있다. 지정한 위젯들은 세로로 배치된다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제목'),
      ),
      body: Column(
        children: <Widget>[
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.green,
            width: 100,
            height: 100,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.blue,
            width: 100,
            height: 100,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
        ],
      )
    );
  }
}

Row

Column과 반대로 수평 방향으로 위젯들을 나란히 배치하는 위젯이다.

Column과 같이 children 프로퍼티에 여러 위젯을 나열한다. Row, Column과 같이 방향성이 있는 위젯은 mainAxis와 crossAxis 관련 프로퍼티가 있다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제목'),
      ),
      body: Row(
        mainAxisSize: MainAxisSize.max,  // 가로로 꽉 채우기
        mainAxisAlignment: MainAxisAlignment.center,  // 가로 방향으로 가운데 정렬
        crossAxisAlignment: CrossAxisAlignment.center, // 세로 방향으로 가운데 정렬
        children: <Widget>[
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.green,
            width: 100,
            height: 100,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.blue,
            width: 100,
            height: 100,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
        ],

      ),
    );
  }
}

mainAxis는 위젯의 기본 방향을 나타낸다. Row는 오른쪽, Column은 아래쪽이 mainAxis가 된다. crossAxis는 기본 방향의 반대 방향을 가타낸다. Row는 아래쪽, Column은 오른쪽이 crossAxis가 된다.

각 프로퍼티에 지정할 수 있는 상수는 다음과 같다.

* MainAxisSize에 정의된 상수

상수 설명
max 최대 크기. 남은 공간을 모두 차지한다.
min  최소 크기. 포함된 콘텐츠의 크기만큼만 차지한다.

* MainAxisAlignment와 CrossAxisAlignment에 정의된 상수

상수 설명
center 가운데 정렬
start 왼쪽 정렬
end 오른쪽 정렬
spaceEvenly
spaceBetween
spaceAround
자식 간의 공간을 어떻게 분배하느냐가 조금씩 다르므로 직접 적용 후 필요한 것을 사용하면 된다.

Stack

Stack 위젯은 children에 나열한 여러 위젯을 순서대로 겹치게 한다. 예를 들어 사진 위에 글자를 표현하거나 화면 위로 로딩 표시를 하는 상황에 사용할 수 있다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제목'),
      ),
      body: Stack(
        children: <Widget>[
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.green,
            width: 80,
            height: 80,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.blue,
            width: 60,
            height: 60,
            padding: const EdgeInsets.all(8.0),
            margin: const EdgeInsets.all(8.0),
          )
        ],
      )
    );
  }
}

SingleChildScrollView

Column을 사용하여 위젯들을 나열하다가 화면 크기를 넘어서면 스크롤이 필요하다. 그럴 때는 SingleChildScrollView로 감싸서 스크롤이 가능하게 할 수 있다. SingleChildScrollView는 말 그대로 하나의 자식을 포함하는 스크롤 가능한 위젯이다.

SingleChildScrollView는 하나의 자식 위젯을 가져야 하기 때문에 Column을 사용하여 상하 스크롤을 구현할 수 있지만, 예제에서는 Column 대신 ListBody를 사용했다. Column은 기본적으로 표시할 위젯의 크기만큼 가로 길이를 가진다. 따라서 스크롤 가능 영역이 좁을 수 있다. ListBoy를 사용하면 스크롤 가능 영역이 가로로 꽉 차기 때문에 사용자가 스크롤하기 더 쉽다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  // 0~99 까지의 값을 갖는 리스트 생성
  final List<int> items = List<int>.generate(100, (index) => index).toList();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제목'),
      ),
      body: SingleChildScrollView(
        child: ListBody(
          children: items.map((i) => Text('숫자 $i')).toList(),
        ),
      )
    );
  }
}

ListView, ListTile

ListView는 리스트를 표시하는 위젯이다. SingleChildScrollView와 ListBody의 조합과 동일한 효과를 내지만 좀 더 리스트 표현에 최적화된 위젯이다.

ListView에 표시할 각 항목의 레이아웃은 직접 정의해도 되지만 리스트 아이템을 쉽게 작성할 수 있는 ListTile 위젯을 사용하면 편리하다. 이 둘을 조합하면 표준적인 리스트를 쉽게 만들 수 있다. ListView의 children 프로퍼티에 다수의 위젯을 배치하면 정적인 리스트를 쉽게 만들 수 있다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제목'),
      ),
      body: ListView(
        scrollDirection: Axis.vertical,
        children: <Widget>[
          ListTile(
            leading: Icon(Icons.home),
            title: Text('Home'),
            trailing: Icon(Icons.navigate_next),
            onTap: (){},
          ),
          ListTile(
            leading: Icon(Icons.event),
            title: Text('Event'),
            trailing: Icon(Icons.navigate_next),
            onTap: (){},
          ),
          ListTile(
            leading: Icon(Icons.camera),
            title: Text('Camera'),
            trailing: Icon(Icons.navigate_next),
            onTap: (){},
          ),
        ],
      )
    );
  }
}

ListTile 위젯은 leading, title, trailing 프로퍼티가 각각 왼쪽, 중앙, 오른쪽 위치를 담당해 자유롭게 아이콘이나 글자를 배치할 수 있다. ListTile의 onTap 프로퍼티에는 리스트의 항목을 탭(tap, 터치) 했을 때 실행해야 하는 동작을 정의한 함수를 작성한다.

이벤트

onPressed, onChanged, onTap 처럼 on으로 시작하는 프로퍼티에 작성한 함수는 사용자 동작에 의해 호출된다. 
어떤 동작에 의해 수행되기 때문에 클릭 이벤트, 변경 이벤트, 탭 이벤트 등으로 부르기도 한다.

GridView

열 수를 지정하여 그리드 형태로 표시하는 위젯이다. 

GridView.count() 생성자는 간단하게 그리드를 작성하게 해준다. crossAxisCount 프로퍼티에 열 수를 지정할 수 있다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제목'),
      ),
      body: GridView.count(
        crossAxisCount: 2,    // 열 수
        children: <Widget>[
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
            padding: new EdgeInsets.all(8.0),
            margin: new EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.green,
            width: 100,
            height: 100,
            padding: new EdgeInsets.all(8.0),
            margin: new EdgeInsets.all(8.0),
          ),
          Container(
            color: Colors.blue,
            width: 100,
            height: 100,
            padding: new EdgeInsets.all(8.0),
            margin: new EdgeInsets.all(8.0),
          ),
        ],
      )
    );
  }
}

PageView

여러 페이지를 좌우로 슬라이드하여 넘길 수 있도록 해주는 위젯이다.

children 프로퍼티에 각 화면을 표현할 위젯을 여러 개 준비하여 지정하면 화면을 좌우로 슬라이드할 수 있다. 하지만 Tab과 연동하여 사용하지 않으면 좌우로 슬라이드가 가능한 지 사용자가 모를 수 있어서 단독으로는 잘 사용하지 않는다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('제목'),
      ),
      body: PageView(
        children: <Widget>[
          Container(
            color: Colors.red,
          ),
          Container(
            color: Colors.green,
          ),
          Container(
            color: Colors.blue,
          ),
        ],
      )
    );
  }
}

AppBar, TabBar, Tab, TabBarView

이 위젯들을 조합하여 PageView와 유사하지만 페이지와 탭이 연동되는 화면을 구성할 수 있다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(    // Scaffold를 감싼다.
        length: 3,                  // 탭의 개수 지정
        child: Scaffold(
          appBar: AppBar(
            title: Text('TabBar 테스트'),
            bottom: TabBar(       // Scaffold의 bottom 프로퍼티에 TabBar 지정
              tabs: <Widget>[     // tabs 프로퍼티에 Tab의 리스트 지정
                Tab(text: 'tab1',),
                Tab(icon: Icon(Icons.ac_unit), text: 'tab2',),
                Tab(icon: Icon(Icons.access_time_sharp),),
              ],
            ),
          ),
          body: TabBarView(       // Scaffold의 body 프로퍼티에는 TabBarView 배치
            children: <Widget>[   // children 프로퍼티에 표시할 화면 배치
              Container(color: Colors.orange,),
              Container(color: Colors.black26,),
              Container(color: Colors.yellow,),
            ],
          ),
        ),
    );
  }
}

Scaffold를 DefaultTabController로 감싸야 하는 것에 주의해야 한다. 탭이 있기 때문에 PageView만 단독으로 사용하는 것보다 이쪽이 사용성이 더 높다. 탭에는 아이콘이나 글자를 표시할 수 있다.


BottomNavigationBar

하단에 2~5개의 탭 메뉴를 구성할 수 있는 위젯이다. 각 탭을 클릭하여 화면을 전환할 때 사용한다.

Scaffold의 프로퍼티 중에서 bottomNavigationBar 프러퍼티를 정의하고 items 프로퍼티에 BottomNavigationBarItem 위젯들을 나열한다. icon과 title 프로퍼티를 정의하여 간단히 하단 탭 바를 구성할 수 있다. 최근에 Android와 iOS 모두에서 자주 사용하는 UI이다.

다음 예제는 body 프로퍼티를 사용하지 않은 Scaffold 전체 코드이다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('플러터 테스트'),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('Home'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            title: Text('Profile'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.notifications),
            title: Text('Notification'),
          ),
        ],
      ),
    );
  }
}


위치, 정렬, 크기를 위한 위젯

화면을 구성할 때는 배치한 위젯의 위치를 정해야 한다. 위젯 중에는 위젯 크기나 위치, 정렬 등을 보조하는 위젯이 있다. 위젯을 중앙에 배치하거나, 한쪽 방향으로 정렬하거나, 위젯 사이에 여백을 주거나, 위젯을 특정 크기로 만들고 싶을 때 사용하는 위젯을 알아보자.

Center

중앙으로 정렬시키는 위젯이다. 상당히 자주 사용하는 위젯이다. child 프로퍼티에 중앙에 배치할 위젯을 설정한다.

Center(
  child: [위젯],
),

그럼 빨간 사각형을 중아에 표시하는 예제를 보자.

Center(
  child: Container(
    color: Colors.red,
    width: 100,
    height: 100,
  ),
),

Padding

안쪽 여백을 표현할 때 사용하는 위젯이다.

안쪽 여백은 padding 프로퍼티에 값을 지정한다. 이 값은 EdgeInsets 클래스를 사용하여 설정하며 다음과 같이 여러 방법을 제공한다. 앞에 const를 붙이면 컴파일 타임에 상수로 정의되어 다시 사용되는 부분이 있을 경우 메모리에 있는 값을 재사용하는 이득이 있다.

Padding(
  padding: const EdgeInsets.all(40.0),
  child: [위젯],
),

EdgeInsets는 여러 함수를 제공한다. all() 함수는 네 방향 모두 같은 값을 지정한다.

EdgeInsets.all([double])

only() 함수는 상하좌우 중에서 원하는 방향에만 값을 지정한다. 지정하지 않은 방향에는 기본값 0.0이 지정된다.

EdgeInsets.only({left: [왼쪽], top: [위], right: [오른쪽], bottom: [아래]})

fromLTRB() 함수는 네 방향의 값을 각각 지정한다.

EdgeInsets.fromLTRB([왼쪽], [위], [오른쪽], 아래])

빨간 사각형의 사방에 50만큼 패딩을 적용하는 예제를 보자.

Padding(
  padding: const EdgeInsets.all(50.0),
  child: Container(
    color: Colors.red,
  ),
),

Align

자식 위젯의 정렬 방향을 정할 수 있는 위젯이다. 원하는 방향으로 위젯을 정렬할 때 사용한다. 자식 위젯을 정렬하기 위해서는 alignment 프로퍼티에 정렬하고자 하는 방향을 정의해야 한다.

Align(
  alignment: Alignment.bottomRight,
  child: [위젯],
),

alignment 프로퍼티에 정의할 수 있는 값들은 Alignment 클래스에 정의되어 있다.

상수 설명
bottomLeft 하단 왼쪽
bottomCenter 하단 중앙
bottomRight 하단 오른쪽
centerLeft 중단 왼쪽
center 중단 중앙
centerRight 중단 오른쪽
topLeft 상단 왼쪽
topCenter 상단 중앙
topRight 상단 오른쪽

하단 오른쪽 빨간 박스를 정렬하는 예제를 보자.

Align(
  alignment: Alignment.bottomRight,
  child: Container(
    color: Colors.red,
    width: 100,
    height: 100,
  ),
),

Expanded

자식 위젯의 크기를 최대한으로 확장시켜주는 위젯이다. 여러 위젯에 동시에 적용하면 flex 프로퍼티에 정수값을 지정하여 비율을 정할 수 있으며 기본 값은 1이다.

Column(
  children: <Widget>[
    Expanded(
     flex: [비율],  // 기본값은 1
     child: [위젯],
    ),
    Expanded(
      child: [위젯],
    ),
    Expanded(
      child: [위젯],
    ),
  ],
),

빨강, 초록, 파랑 박스를 2:1:1 비율의 배치 예제를 보자.

Column(
  children: <Widget>[
    Expanded(
      flex: 2,
      child: Container(
        color: Colors.red,
      ),
    ),
    Expanded(
      child: Container(
        color: Colors.green,
      ),
    ),
    Expanded(
      child: Container(
        color: Colors.blue,
      ),
    ),
  ],
),

SizedBox

위젯 중에는 크기에 관련된 프로퍼티가 없는 위젯이 많은데 그러한 위젯을 특정 크기로 만들고 싶을 때 사용한다.

width에 가로 길이, height에 세로 길이를 double 타입으로 지정한다. SizedBox를 child 없이 단독으로 사용하면 단순히 여백을 표현하는 데 사용할 수 있다.

SizedBox(
  width: [가로 길이],
  height: [세로 길이],
  child: [위젯],
),

빨간 박스를 100, 100 크기로 만드는 예제를 보자.

SizedBox(
  width: 100,
  height: 100,
  child: Container(
    color: Colors.red;
  ),
),

이전처럼 Container에 길이를 직접 지정하면 코드가 더 간결해지지만 대부분의 위젯은 크기 지정 프로퍼티를 가지고 있지 않기 때문에 SizedBox를 많이 사용한다.


Card

카드 형태의 모양을 제공하는 위젯이다. 기본적으로 크기가 0이므로 자식 위젯의 크기에 따라 크기가 결정된다.

Card(
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius..circular(16.0),
  ),
  elevation: [실수값],  // 그림자 깊이
  child: [위젯],
),
  • elevation 프로퍼티를 지정하여 그림자의 깊이를 조정할 수 있다. 좀 더 깊은 그림자를 표현하려면 좀 더 큰 값을 지정한다.
  • shape 프로퍼티는 카드 모양을 변경하는 방법을 제공하며, 여기서는 RoundedRectangleBorder 클래스의 인스턴스를 지정했다. 이 클래스는 borderRadius 프로퍼티에 BorderRadius.circular() 메소드를 지정하여 카드 모서리의 둥근 정도를 실수값을 조절한다. 값이 클수록 더 둥글게 된다.

카드 위젯을 화면 중앙에 배치하는 예제를 보자.

Center(
  child: Card(
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(18.0),
    ),
    elevation: 5.0  // 그림자 깊이
    child: Container(
      width: 200,
      height: 200,
    ),
  ),
),

버튼 계열 위젯

플러터는 여러 종류의 버튼 위젯을 제공한다. 그 중 가장 많이 사용하는 버튼을 소개한다.

RaisedButton

입체감을 가지는 일반적인 버튼 위젯이다. 버튼 위젯들은 onPressed 프로퍼티에 버튼이 클릭되었을 때 실행될 함수를 반드시 정의해줘야 버튼이 활성화되며 클릭 가능하다. 만약 null을 지정하면 버튼일 클릭되지 않는 비활성화 상태가 된다.

RaiseButton(
  child: Text('RaisedButton'),
  color: Colors.orange,
  onPressed: () {
    // 실행될 코드
  },
),

FlatButton

평평한 형태의 버튼이다.

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

IconButton

아이콘을 표시하는 버튼 위젯이다.

IconButton(
  icon: Icon(Icons.add),
  color: Colors.red,
  iconSize: 100.0,
  onPressed: () {},
),

아이콘의 크기나 색을 지정할 수 있다. 이 위젯은 다른 위젯과 다르게 자식 위젯을 포함할 수 없기 때문에 chlid 프로퍼티가 없다. 대신 아이콘을 icon 프로퍼티에 작성하고 크기는 iconSize 프로퍼티로 설정한다.


FloatingActionButton

입체감 있는 둥근 버튼 위젯이다. 아이콘을 표시하는 데 사용한다. Scaffold의 floatingActionButton 프로퍼티에 바로 사용할 수 있고, 일반적인 버튼처럼 단독 사용할 수도 있다.

FloatingActionButton(
  child: Icon(Icons.add),
  onPressed: () {},
),

화면 표시용 위젯

버튼과 더불어 화면 구성시 가장 자주 사용되는 위젯인 텍스트, 이미지, 아이콘, 프로그레스바를 알아보자.

Text

글자를 표시하는 위젯이다. 

Text(
  'Hello World',
  style: TextStyle(
    fontSize: 40.0,
    fontStyle: FontStyle.italic,
    fontWeight: FontWeight.bold,
    color: Colors.red,
    letterSpacing: 4.0,
  ),
),

Text 위젯은 기본적으로 첫 번째 인수에 문자열을 지정하여 Text('글자') 형태로 사용하는데 style 프로퍼티에 TextStyle 클래스의 인스턴스를 지정하여 다양한 글자를 표현할 수 있다. TextStyle 클래스는 글자 크기, 색상, 폰트 스타일 등을 쉽게 설정할 수 있다.

참고로 Text 클래스의 첫 번째 인수는 필수 프로퍼티고 이름 없는 인수이다. style뿐만 아니라 모든 이름 있는 인수는 옵션 성격이므로 필요한 것을 선택적으로 사용할 수 있다.


Image

이미지를 표시하는 위젯이다. 플러터에서는 네트워크에 있는 이미지를 간단히 표시할 수 있다. network() 메소드에 이미지 파일의 URL을 입력하기만 하면 된다.

Image.network('http://bit.ly/2Pvz4t8')  // 이미지 URL

물론 asset() 메소드로 이미지 파일을 직접 표시할 수도 있다. 이미지 파일을 사용하려면 프로젝트 내에 별도의 폴더를 만든 후 이미지 파일을 복사해둔다. 

이미지 파일을 사용할 수 있도록 pubspec.yaml 파일을 수정해야 한다. pubspec.yaml 파일의 flutter: 항목 아래의 assets: 항목 아래에 폴더명을 지정하면 된다. assets/sample.jpg와 같은 형태로 나열해도 되지만 assets/와 같이 전체 폴더를 가리키면 여러 항목을 매 번 작성할 필요가 없다.

flutter:
  assets:
    - assets/

pubspec.yaml 파일을 수정할 때는 들여쓰기에 주의해야 한다. pubspec.yaml 을 수정한 후에는 터미널에서 flutter packages get 명령을 실행하여 프로젝트에서 이미지 파일에 접근할 수 있게 해야 한다. 그런 후 다음과 같이 이미지 파일을 사용할 수 있다.

Image.asset('assets/sample.jpg')

Icon

아이콘 위젯은 단독으로도 사용하지만 메뉴나 리스트, 버튼과의 조합으로 사용한다. 머터리얼 디자인용 기본 아이콘들은 Icons 클래스에 상수로 미리 정의되어 있다. Icon 클래스의 첫 번째 인수에 Colors 클래스에 미리 정의된 다양한 머터리얼 아이콘을 지정한다. 색상이나 크기 등을 자유롭게 지정할 수 있다.

Icon(
  Icons.home,
  color: Colors.red,
  size: 60.0,   // 기본값은 24.0
),

Progress

로딩 중이거나 오래 걸리는 작업을 할 때 사용자에게 진행 중임을 보여주는 용도로 사용하는 위젯이다. 두 종류를 제공한다.

  1. 둥근 형태의 프로그레스바. 일반적으로 다른 화면 위에 겹쳐서 표시하므로 Stack 위젯으로 겹쳐 사용한다.
  2. 선 형태의 프로그레스바
CircularProgressIndicator()
LinearProgressIndicator()

CircleAvatar

프로필 화면 등에 많이 사용하는 원형 위젯이다. chlid 프로퍼티에 정의한 위젯을 원형으로 만들어준다.

CircleAvatar(
  child: Icon(Icons.person),
),

네트워크상에 존재하는 이미지를 표시한다면 child 프로퍼티가 아닌 backgroundIamge 프로퍼티에 NetworkImage 클래스의 인스턴스를 지정해야 네트워크에서 받아온 이미지가 원형으로 표시된다.

CircleAvatar(
  backgroundImage: NetworkImage([이미지 URL]),
),

정리

  • 플러터의 UI를 구성하는 모든 요소를 위젯(Widget)이라고 한다.
  • 위치나 크기 같은 속성 또한 위젯을 사용한다.
Comments