Flutter-레이아웃 소개

Flutter 의 핵심 개념 은 Everything is widget 이므로 Flutter 는 사용자 인터페이스 레이아웃 기능을 위젯 자체에 통합합니다. Flutter 는 사용자 인터페이스를 레이아웃하기위한 목적으로 만 Container, Center, Align 등과 같이 특별히 디자인 된 많은 위젯을 제공합니다. 다른 위젯을 구성하여 빌드하는 위젯은 일반적으로 레이아웃 위젯을 사용합니다. 이 장에서 Flutter 레이아웃 개념을 배우십시오 .

레이아웃 위젯 유형

레이아웃 위젯은 자식을 기준으로 두 개의 별개 카테고리로 그룹화 할 수 있습니다.

  • 한 자녀를 지원하는 위젯
  • 여러 자녀를 지원하는 위젯

다음 섹션에서 위젯 유형과 기능에 대해 알아 보겠습니다.

단일 자식 위젯

이 범주에서 위젯은 자식으로 하나의 위젯 만 가지며 모든 위젯에는 특별한 레이아웃 기능이 있습니다.

예를 들어 Center 위젯은 상위 위젯과 관련하여 하위 위젯을 중앙 에 배치 하고 Container 위젯은 패딩, 장식 등과 같은 다른 옵션을 사용하여 하위 위젯을 내부의 지정된 위치에 배치 할 수있는 완전한 유연성을 제공합니다.

단일 하위 위젯은 버튼, 레이블 등과 같은 단일 기능을 가진 고품질 위젯을 만드는 데 유용한 옵션입니다.

컨테이너 위젯을 사용하여 간단한 버튼을 만드는 코드 는 다음과 같습니다.

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

여기에서는 컨테이너 위젯과 텍스트 위젯 이라는 두 가지 위젯을 사용했습니다 . 위젯의 결과는 아래와 같이 사용자 정의 버튼입니다.

우리가 제공하는 가장 중요한 하나의 아이의 레이아웃 위젯의 일부를 확인하자 플러터를 -

  • Padding− 주어진 패딩으로 자식 위젯을 정렬하는 데 사용됩니다. 여기서 패딩은 EdgeInsets 클래스에서 제공 할 수 있습니다 .

  • Alignalignment 속성 의 값을 사용하여 하위 위젯을 자체적으로 정렬 합니다. 정렬 속성 의 값은 FractionalOffset 클래스에서 제공 할 수 있습니다 . FractionalOffset의 클래스는 왼쪽 상단에서 거리의 측면에서 오프셋을 지정합니다.

가능한 오프셋 값 중 일부는 다음과 같습니다.

  • FractionalOffset (1.0, 0.0)은 오른쪽 상단을 나타냅니다.

  • FractionalOffset (0.0, 1.0)은 왼쪽 하단을 나타냅니다.

오프셋에 대한 샘플 코드는 다음과 같습니다.

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox − 하위 위젯의 크기를 조정 한 다음 지정된 맞춤에 따라 배치합니다.

  • AspectRatio − 하위 위젯의 크기를 지정된 가로 세로 비율로 시도합니다.

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

Hello World 애플리케이션은 재료 기반 레이아웃 위젯을 사용하여 홈페이지를 디자인합니다. 아래에 지정된 기본 레이아웃 위젯을 사용하여 홈페이지를 구축하도록 hello world 애플리케이션을 수정 해 보겠습니다.

  • Container − 풍부한 스타일링 기능과 함께 정렬, 패딩, 테두리 및 여백이있는 일반, 단일 자식, 상자 기반 컨테이너 위젯.

  • Center − 하위 위젯을 중앙에 배치하는 간단한 단일 하위 컨테이너 위젯.

MyHomePageMyApp 위젯 의 수정 된 코드는 다음 과 같습니다.

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

여기,

  • 컨테이너 위젯은 최상위 또는 루트 위젯입니다. 컨테이너 는 내용을 레이아웃하기 위해 장식패딩 속성을 사용하여 구성 됩니다.

  • BoxDecoration컨테이너 위젯 을 꾸미기위한 색상, 테두리 등의 많은 속성을 가지고 있으며 여기서 색상 은 컨테이너의 색상을 설정하는 데 사용됩니다.

  • 패딩컨테이너 를 사용하여 설정 한 위젯 dgeInsets의 패딩 값을 지정하는 옵션을 제공합니다 클래스를.

  • Center컨테이너 위젯 의 하위 위젯입니다 . 다시 말하지만 TextCenter 위젯 의 자식입니다 . 텍스트 는 메시지를 표시하는 데 사용되며 Center 는 상위 위젯 인 Container에 대해 텍스트 메시지를 중앙에 배치하는 데 사용됩니다 .

위에 주어진 코드의 최종 결과는 아래와 같은 레이아웃 샘플입니다.

여러 하위 위젯

이 카테고리에서 주어진 위젯은 둘 이상의 하위 위젯을 가지며 각 위젯의 레이아웃은 고유합니다.

예를 들어 위젯은 자식을 가로 방향으로 배치 할 수있는 반면 위젯은 자식을 세로 방향으로 배치 할 수 있습니다. RowColumn 을 구성 하여 모든 수준의 복잡성을 가진 위젯을 구축 할 수 있습니다.

이 섹션에서 자주 사용되는 위젯에 대해 알아 보겠습니다.

  • Row − 자식을 수평으로 배열 할 수 있습니다.

  • Column − 자식을 수직으로 배열 할 수 있습니다.

  • ListView − 자식을 목록으로 정렬 할 수 있습니다.

  • GridView − 자녀를 갤러리로 정렬 할 수 있습니다.

  • Expanded − 행 및 열 위젯의 자식이 가능한 최대 영역을 차지하도록 만드는 데 사용됩니다.

  • Table − 테이블 기반 위젯.

  • Flow − 흐름 기반 위젯.

  • Stack − 스택 기반 위젯.

고급 레이아웃 애플리케이션

이 섹션에서는 단일 및 다중 하위 레이아웃 위젯을 모두 사용하여 맞춤형 디자인 으로 제품 목록 의 복잡한 사용자 인터페이스를 만드는 방법을 알아 보겠습니다 .

이를 위해 아래 주어진 순서를 따르십시오.

  • Android 스튜디오 product_layout_app 에서 새 Flutter 애플리케이션을 만듭니다 .

  • main.dart 코드를 다음 코드로 교체하십시오.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData( 
         primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • 기본 StatefulWidget 대신 StatelessWidget 을 확장하여 MyHomePage 위젯을 만든 다음 관련 코드를 제거했습니다.

  • 이제 다음과 같이 지정된 디자인에 따라 새 위젯 ProductBox를 만듭니다.

  • ProductBox 의 코드 는 다음과 같습니다.

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • 코드에서 다음을 준수하십시오-

  • ProductBox 는 아래에 지정된 4 개의 인수를 사용했습니다.

    • 이름-제품 이름

    • 설명-제품 설명

    • 가격-제품 가격

    • image-제품 이미지

  • ProductBox 는 아래에 지정된대로 7 개의 내장 위젯을 사용합니다.

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBox 는 위에서 언급 한 위젯을 사용하여 설계되었습니다. 위젯의 배열 또는 계층은 아래 다이어그램에 지정되어 있습니다.

  • 이제 애플리케이션의 assets 폴더에 제품 정보에 대한 더미 이미지 (아래 참조)를 배치하고 아래와 같이 pubspec.yaml 파일의 assets 폴더를 구성하십시오.

assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png

iPhone.png

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

마지막으로, 사용 ProductBox는 에 위젯 MyHomePage 아래에 지정된 위젯 -

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • 여기에서는 ProductBoxListView 위젯의 자식으로 사용했습니다 .

  • 제품 레이아웃 애플리케이션 (product_layout_app) 의 전체 코드 (main.dart) 는 다음과 같습니다.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', theme: ThemeData(
            primarySwatch: Colors.blue,
         ), 
         home: MyHomePage(title: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

응용 프로그램의 최종 출력은 다음과 같습니다.