0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Flet入門] 基本レイアウト(コンテナとフレックス)の使い方

Posted at

はじめに

flet-layout-diagram.png

前回の記事では、FletのインタラクティブなUI要素(ElevatedButton、Checkbox、Switchなど)について紹介しました。今回は、これらの要素を効果的に配置するための基本レイアウトに焦点を当てます。

Fletは、Pythonだけで美しいクロスプラットフォームUIアプリケーションを構築できるフレームワークです。UIを構築する際に重要となるのがレイアウトの考え方です。

今回紹介する基本レイアウト要素は以下の通りです:

  1. Container: 単一の子要素を持つコンテナ
  2. Row, Column: 複数の子要素を水平・垂直に配置
  3. フレックスの考え方: 柔軟なレイアウト
  4. 余白とアライメント: 要素の位置調整

環境構築

まだFletをインストールしていない場合は、以下のコマンドでインストールしましょう。

pip install flet

1. Container - 基本的なコンテナ

Containerは、単一の子要素をラップするための基本的なレイアウト要素です。パディング、マージン、背景色、ボーダーなどのスタイリングを適用できます。

基本的な使い方

import flet as ft

def main(page: ft.Page):
    # 基本的なコンテナ
    basic_container = ft.Container(
        content=ft.Text("こんにちは、Flet!"),
        width=200,
        height=100,
        bgcolor=ft.Colors.BLUE_100,
        border_radius=10,
        padding=20,
        alignment=ft.alignment.center,
    )
    
    page.add(basic_container)

ft.app(target=main)

コンテナの主要プロパティ

  • content: コンテナ内に配置する子要素
  • width, height: 幅と高さ
  • bgcolor: 背景色
  • border_radius: 角の丸み
  • border: ボーダー設定
  • padding: 内側の余白
  • margin: 外側の余白
  • alignment: 子要素の配置位置

2. Row, Column - 複数要素の配置

RowColumnは、複数の子要素を水平方向(Row)または垂直方向(Column)に配置するためのレイアウト要素です。

Rowの基本的な使い方

# 水平方向の配置
row = ft.Row(
    controls=[
        ft.Container(width=50, height=50, bgcolor=ft.Colors.RED),
        ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
        ft.Container(width=50, height=50, bgcolor=ft.Colors.BLUE),
    ],
    spacing=10,  # 要素間の間隔
)

Columnの基本的な使い方

# 垂直方向の配置
column = ft.Column(
    controls=[
        ft.Container(width=50, height=50, bgcolor=ft.Colors.RED),
        ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
        ft.Container(width=50, height=50, bgcolor=ft.Colors.BLUE),
    ],
    spacing=10,  # 要素間の間隔
)

3. フレックスの考え方

Fletのレイアウトシステムは、Flutterのフレックスボックスに基づいています。これにより、様々な画面サイズに対応する柔軟なレイアウトが可能になります。

主軸と交差軸

  • 主軸 (Main Axis):

    • Rowでは水平方向
    • Columnでは垂直方向
  • 交差軸 (Cross Axis):

    • Rowでは垂直方向
    • Columnでは水平方向

主軸でのアライメント

Rowを例にした主軸でのアライメントオプションです:

# MainAxisAlignment.START(デフォルト)
# 要素が主軸の始点から配置される
row_start = ft.Row(
    [ft.Container(width=50, height=50, bgcolor=ft.Colors.RED),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.BLUE)],
    alignment=ft.MainAxisAlignment.START,
    width=400,
    bgcolor=ft.Colors.AMBER_100,
)

# MainAxisAlignment.CENTER
# 要素が主軸の中央に配置される
row_center = ft.Row(
    [ft.Container(width=50, height=50, bgcolor=ft.Colors.RED),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.BLUE)],
    alignment=ft.MainAxisAlignment.CENTER,
    width=400,
    bgcolor=ft.Colors.AMBER_100,
)

# MainAxisAlignment.END
# 要素が主軸の終点に配置される
row_end = ft.Row(
    [ft.Container(width=50, height=50, bgcolor=ft.Colors.RED),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.BLUE)],
    alignment=ft.MainAxisAlignment.END,
    width=400,
    bgcolor=ft.Colors.AMBER_100,
)

# MainAxisAlignment.SPACE_BETWEEN
# 最初と最後の要素は端に配置され、残りの要素は等間隔に配置される
row_space_between = ft.Row(
    [ft.Container(width=50, height=50, bgcolor=ft.Colors.RED),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.BLUE)],
    alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
    width=400,
    bgcolor=ft.Colors.AMBER_100,
)

交差軸でのアライメント

# CrossAxisAlignment.START
# 要素が交差軸の始点に配置される
row_cross_start = ft.Row(
    [ft.Container(width=50, height=30, bgcolor=ft.Colors.RED),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
     ft.Container(width=50, height=70, bgcolor=ft.Colors.BLUE)],
    vertical_alignment=ft.CrossAxisAlignment.START,
    height=100,
    bgcolor=ft.Colors.AMBER_100,
)

# CrossAxisAlignment.CENTER(デフォルト)
# 要素が交差軸の中央に配置される
row_cross_center = ft.Row(
    [ft.Container(width=50, height=30, bgcolor=ft.Colors.RED),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
     ft.Container(width=50, height=70, bgcolor=ft.Colors.BLUE)],
    vertical_alignment=ft.CrossAxisAlignment.CENTER,
    height=100,
    bgcolor=ft.Colors.AMBER_100,
)

# CrossAxisAlignment.END
# 要素が交差軸の終点に配置される
row_cross_end = ft.Row(
    [ft.Container(width=50, height=30, bgcolor=ft.Colors.RED),
     ft.Container(width=50, height=50, bgcolor=ft.Colors.GREEN),
     ft.Container(width=50, height=70, bgcolor=ft.Colors.BLUE)],
    vertical_alignment=ft.CrossAxisAlignment.END,
    height=100,
    bgcolor=ft.Colors.AMBER_100,
)

要素のフレックス比率

expandプロパティを使用すると、要素が利用可能なスペースをどれだけ占めるかを指定できます。

# フレックス比率の例
flex_row = ft.Row([
    # 1の比率で拡大
    ft.Container(
        content=ft.Text("1"),
        bgcolor=ft.Colors.RED,
        alignment=ft.alignment.center,
        expand=1,
    ),
    # 2の比率で拡大(最初の要素の2倍のスペースを占める)
    ft.Container(
        content=ft.Text("2"),
        bgcolor=ft.Colors.GREEN,
        alignment=ft.alignment.center,
        expand=2,
    ),
    # 1の比率で拡大
    ft.Container(
        content=ft.Text("1"),
        bgcolor=ft.Colors.BLUE,
        alignment=ft.alignment.center,
        expand=1,
    ),
], height=50)

要素のラップ(折り返し)

wrapプロパティをTrueに設定すると、要素が収まらない場合に自動的に折り返されます。

# 要素の折り返し
wrap_row = ft.Row(
    [
        ft.Container(width=100, height=50, bgcolor=ft.Colors.RED),
        ft.Container(width=100, height=50, bgcolor=ft.Colors.GREEN),
        ft.Container(width=100, height=50, bgcolor=ft.Colors.BLUE),
        ft.Container(width=100, height=50, bgcolor=ft.Colors.YELLOW),
        ft.Container(width=100, height=50, bgcolor=ft.Colors.ORANGE),
    ],
    wrap=True,  # 収まらない要素を折り返す
    spacing=10,
    run_spacing=10,  # 折り返し行の間隔
)

4. 余白とアライメント

マージンとパディング

Fletでは、marginpaddingを使って要素の周りや内側に余白を設定できます。

# マージンとパディングの例
container = ft.Container(
    content=ft.Text("Hello, Flet!"),
    margin=20,  # 外側の余白
    padding=20,  # 内側の余白
    bgcolor=ft.Colors.AMBER_100,
)

特定の方向にのみ余白を設定

# 上下にのみマージンを設定
custom_margin = ft.Container(
    content=ft.Text("上下にのみマージン"),
    margin=ft.margin.only(top=20, bottom=20),
    bgcolor=ft.Colors.GREEN_100,
    padding=10,
)

# 左右にのみパディングを設定
custom_padding = ft.Container(
    content=ft.Text("左右にのみパディング"),
    padding=ft.padding.only(left=20, right=20),
    bgcolor=ft.Colors.PURPLE_100,
)

要素の配置位置

alignmentプロパティを使用して、コンテナ内での子要素の配置位置を指定できます。

# 中央揃え
center_container = ft.Container(
    content=ft.Text("中央揃え"),
    alignment=ft.alignment.center,
    width=200,
    height=100,
    bgcolor=ft.Colors.BLUE_100,
)

# 左上揃え
top_left_container = ft.Container(
    content=ft.Text("左上揃え"),
    alignment=ft.alignment.top_left,
    width=200,
    height=100,
    bgcolor=ft.Colors.BLUE_100,
)

# 右下揃え
bottom_right_container = ft.Container(
    content=ft.Text("右下揃え"),
    alignment=ft.alignment.bottom_right,
    width=200,
    height=100,
    bgcolor=ft.Colors.BLUE_100,
)

実践的な例: レスポンシブカード

image.png

以下の例では、これまで学んだレイアウト要素を組み合わせて、視認性の高いレスポンシブなカードUIを作成します。

import flet as ft

def main(page: ft.Page):
    page.title = "レスポンシブカードUI"
    page.padding = 20
    page.bgcolor = ft.Colors.BLACK
    page.theme_mode = ft.ThemeMode.DARK
    
    # ウィンドウサイズ変更時のハンドラ
    def on_resize(e):
        # 画面幅に応じてカードの幅を調整
        if page.width < 600:
            # モバイル表示
            info_card.width = page.width - 40
            header_row.alignment = ft.MainAxisAlignment.CENTER
            actions_row.alignment = ft.MainAxisAlignment.CENTER
        else:
            # デスクトップ表示
            info_card.width = min(page.width - 40, 600)
            header_row.alignment = ft.MainAxisAlignment.START
            actions_row.alignment = ft.MainAxisAlignment.END
        
        page.update()
    
    # ページのリサイズイベントを監視
    page.on_resize = on_resize
    
    # ヘッダー行
    header_row = ft.Row([
        ft.Icon(ft.Icons.INFO, color=ft.Colors.WHITE, size=24),
        ft.Text("情報カード", color=ft.Colors.WHITE, weight="bold", size=18),
    ], alignment=ft.MainAxisAlignment.START)
    
    # 確認ボタン
    confirm_button = ft.ElevatedButton(
        "確認",
        style=ft.ButtonStyle(
            color={"": ft.Colors.WHITE},
            bgcolor={"": ft.Colors.BLUE, "hovered": ft.Colors.BLUE_700},
            elevation={"pressed": 0, "": 5},
            animation_duration=300,
        ),
    )
    
    actions_row = ft.Row(
        [confirm_button],
        alignment=ft.MainAxisAlignment.END,
    )
    
    # カードUI - コントラスト改善版
    info_card = ft.Container(
        content=ft.Column([
            # カードヘッダー - グラデーション背景
            ft.Container(
                content=header_row,
                gradient=ft.LinearGradient(
                    begin=ft.alignment.center_left,
                    end=ft.alignment.center_right,
                    colors=[ft.Colors.BLUE_700, ft.Colors.BLUE_900],
                ),
                padding=15,
                border_radius=ft.border_radius.only(top_left=10, top_right=10),
            ),
            
            # カードコンテンツ
            ft.Container(
                content=ft.Column([
                    ft.Text(
                        "Fletの基本レイアウト要素の例です",
                        size=16,
                        weight="bold",
                        color=ft.Colors.BLACK,  # 黒色でコントラスト向上
                    ),
                    ft.Container(height=15),  # スペーサー
                    
                    # リストアイテム - アイコン付き、文字色を濃く
                    ft.Row([
                        ft.Icon(ft.Icons.LAYERS, color=ft.Colors.BLUE_700, size=20),
                        ft.Text("Container: カード全体のコンテナ", 
                              color=ft.Colors.BLACK,
                              size=14,
                              weight="w500"),  # 文字列として指定
                    ], vertical_alignment=ft.CrossAxisAlignment.CENTER, spacing=10),
                    
                    ft.Row([
                        ft.Icon(ft.Icons.GRID_VIEW, color=ft.Colors.BLUE_700, size=20),
                        ft.Text("Row, Column: 要素の配置", 
                              color=ft.Colors.BLACK,
                              size=14,
                              weight="w500"),
                    ], vertical_alignment=ft.CrossAxisAlignment.CENTER, spacing=10),
                    
                    ft.Row([
                        ft.Icon(ft.Icons.SPACE_DASHBOARD, color=ft.Colors.BLUE_700, size=20),
                        ft.Text("マージンとパディング: 適切な余白", 
                              color=ft.Colors.BLACK,
                              size=14,
                              weight="w500"),
                    ], vertical_alignment=ft.CrossAxisAlignment.CENTER, spacing=10),
                    
                    ft.Row([
                        ft.Icon(ft.Icons.ASPECT_RATIO, color=ft.Colors.BLUE_700, size=20),
                        ft.Text("レスポンシブ: 画面サイズに適応", 
                              color=ft.Colors.BLACK,
                              size=14,
                              weight="w500"),
                    ], vertical_alignment=ft.CrossAxisAlignment.CENTER, spacing=10),
                    
                    ft.Container(height=20),  # スペーサー
                    
                    # アクションボタン
                    actions_row,
                ], spacing=15),  # 行間を広げる
                padding=20,
                bgcolor=ft.Colors.WHITE,
            ),
        ]),
        width=500,  # 初期幅(on_resizeでウィンドウサイズに応じて調整)
        border_radius=10,
        shadow=ft.BoxShadow(
            spread_radius=1,
            blur_radius=15,
            color=ft.Colors.BLACK38,
            offset=ft.Offset(0, 5),
        ),
    )
    
    # ページに追加
    page.add(info_card)
    
    # 初期サイズに合わせてレイアウトを調整
    on_resize(None)

ft.app(target=main)

この例では、以下のポイントに注目しています:

  1. レスポンシブ対応

    • on_resize関数で画面幅を検出
    • 小さい画面(600px未満)と大きい画面で異なるレイアウトを適用
    • カードの幅を画面サイズに合わせて調整
  2. 視認性の向上

    • 文字色を濃くしてコントラストを高める
    • アイコンにも濃い色を使用
    • 行間を広げて読みやすさを向上
  3. 魅力的なデザイン

    • ヘッダー部分にグラデーション背景
    • 立体感のある影効果
    • アイコンを使って視覚的な魅力を向上
  4. コントラストの確保

    • 背景色と文字色の組み合わせで高いコントラストを実現
    • フォントサイズとウェイトを適切に設定

まとめ

flet-layout-summary.png

Fletの基本レイアウト要素について解説しました。

  • Container: 単一の子要素をラップし、スタイリングを適用
  • Row, Column: 複数の子要素を水平・垂直に配置
  • フレックスの考え方: 主軸と交差軸でのアライメント、比率による拡大、折り返し
  • 余白とアライメント: マージン、パディング、配置位置の調整

これらの要素を組み合わせることで、柔軟で美しいUIレイアウトを作成できます。レスポンシブデザインの実装も、基本的なレイアウト要素の理解があれば難しくありません。視認性とコントラストを考慮したデザインは、すべてのユーザーにとって使いやすいUIを提供します。

免責事項

  • 本記事の作成にあたり、文章や図解の生成に生成AIを活用しました。最終的な編集と確認は筆者が行っています。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?