Flutter-レイアウトの概要
Flutterのコアコンセプトはすべてがウィジェットであるため、Flutterはユーザーインターフェイスのレイアウト機能をウィジェット自体に組み込んでいます。Flutterは、ユーザーインターフェイスをレイアウトする目的でのみ、Container、Center、Alignなどの特別に設計されたウィジェットを多数提供します。他のウィジェットを構成することによって構築されるウィジェットは、通常、レイアウトウィジェットを使用します。この章でフラッターレイアウトの概念を学びましょう。
レイアウトウィジェットの種類
レイアウトウィジェットは、その子に基づいて2つの異なるカテゴリにグループ化できます-
- 一人っ子をサポートするウィジェット
- 複数の子をサポートするウィジェット
次のセクションでは、ウィジェットのタイプとその機能の両方を学びましょう。
シングルチャイルドウィジェット
このカテゴリでは、ウィジェットの子としてウィジェットが1つだけになり、すべてのウィジェットに特別なレイアウト機能があります。
たとえば、センターウィジェットは、親ウィジェットに対して子ウィジェットを中央に配置するだけであり、コンテナウィジェットは、パディング、装飾などのさまざまなオプションを使用して、子ウィジェットをその中の任意の場所に配置する完全な柔軟性を提供します。
単一の子ウィジェットは、ボタン、ラベルなどの単一の機能を備えた高品質のウィジェットを作成するための優れたオプションです。
コンテナウィジェットを使用して単純なボタンを作成するコードは次のとおりです-
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)
),
),
);
}
}
ここでは、コンテナウィジェットとテキストウィジェットの2つのウィジェットを使用しました。ウィジェットの結果は、以下に示すようにカスタムボタンとして表示されます-
Flutterが提供する最も重要なシングルチャイルドレイアウトウィジェットのいくつかを確認しましょう-
Padding−指定されたパディングによって子ウィジェットを配置するために使用されます。ここで、パディングはEdgeInsetsクラスによって提供できます。
Align−アライメントプロパティの値を使用して、子ウィジェットをそれ自体の中で整列させます。配置プロパティの値は、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
私たちのhelloworldアプリケーションは、マテリアルベースのレイアウトウィジェットを使用してホームページをデザインしています。以下に指定する基本的なレイアウトウィジェットを使用してホームページを構築するように、HelloWorldアプリケーションを変更してみましょう-
Container −豊富なスタイリング機能に加えて、配置、パディング、境界線、マージンを備えた、汎用のシングルチャイルドボックスベースのコンテナウィジェット。
Center −子ウィジェットを中央に配置するシンプルな単一の子コンテナウィジェット。
MyHomePageおよびMyAppウィジェットの変更されたコードは次のとおりです-
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は、Containerウィジェットの子ウィジェットです。繰り返しますが、テキストはセンターウィジェットの子です。テキストはメッセージを表示するために使用され、Centerは親ウィジェットContainerに関してテキストメッセージを中央に配置するために使用されます。
上記のコードの最終結果は、以下に示すレイアウトサンプルです。
複数の子ウィジェット
このカテゴリでは、特定のウィジェットに複数の子ウィジェットがあり、各ウィジェットのレイアウトは一意です。
たとえば、行ウィジェットでは子を水平方向にレイアウトできますが、列ウィジェットでは子を垂直方向にレイアウトできます。行と列を構成することにより、あらゆるレベルの複雑さを持つウィジェットを構築できます。
このセクションでは、頻繁に使用されるウィジェットのいくつかを学びましょう。
Row −子を水平に配置できます。
Column −子を垂直に配置できます。
ListView −子をリストとして配置できます。
GridView −子をギャラリーとして配置できます。
Expanded −行ウィジェットと列ウィジェットの子が可能な最大領域を占めるようにするために使用されます。
Table −テーブルベースのウィジェット。
Flow −フローベースのウィジェット。
Stack −スタックベースのウィジェット。
高度なレイアウトアプリケーション
このセクションでは、単一の子レイアウトウィジェットと複数の子レイアウトウィジェットの両方を使用して、カスタムデザインで製品リストの複雑なユーザーインターフェイスを作成する方法を学びましょう。
この目的のために、以下に示す順序に従ってください-
AndroidStudioで新しいFlutterアプリケーション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(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つの引数を使用しています-
名前-製品名
説明-製品の説明
価格-製品の価格
画像-製品の画像
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"
),
],
)
);
}
}
ここでは、ListViewウィジェットの子としてProductBoxを使用しました。
製品レイアウトアプリケーション(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()
),
],
)
)
)
]
)
)
);
}
}
アプリケーションの最終出力は次のとおりです-