0
0

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入門] レイアウトの実装 GridView、Stack、Cardの活用法

Last updated at Posted at 2025-04-24

はじめに

image.png

Fletは、Pythonだけでクロスプラットフォームのアプリケーションを構築できる強力なツールです。今回は、レイアウト要素に焦点を当て、特に視認性の問題を解決するテクニックをご紹介します:

Fletのレイアウト要素一覧

image.png

レイアウト要素 核となる特徴 視認性向上のポイント
GridView 格子状に要素を整然と配置する • 適切な間隔(spacing)の設定
• 背景色と文字色のコントラスト
Stack 複数要素を同じ空間に重ねて表示 • 半透明オーバーレイ(#66000000)
• テキスト背景の追加(#99000000)
Card 影とボーダーで浮き上がった表現 • 適切なパディング
• 高さとコンテンツの自動調整
組み合わせ 階層構造による複合的な表現 • 下部のみ暗くするグラデーション
• テキスト要素の視覚的分離

Fletを使えば、純粋なPythonコードだけでこれらの高度なレイアウトを実現できます。フロントエンド技術の知識がなくても、美しいアプリケーションが構築できるのが魅力です。

サンプルコードの実行例

image.png

image.png

image.png

image.png

環境構築

pip install flet

バージョンの注意点:

  • バージョン0.25.0以降: ft.colorsft.Colors, ft.iconsft.Icons
  • 各バージョンによって利用できるプロパティやAPIが異なる場合があります
  • サンプルコードはflet 0.25.0以降を想定しています

1. GridView(グリッドレイアウト)

GridViewは項目を格子状に配置するレイアウトです。写真ギャラリーやダッシュボードに最適です。

基本的な使い方

ft.GridView(
    runs_count=4,           # 行または列の数
    max_extent=150,         # 各アイテムの最大幅
    child_aspect_ratio=1.0, # 子要素のアスペクト比(幅/高さ)
    spacing=15,             # 水平方向の間隔
    run_spacing=15,         # 垂直方向の間隔
    controls=[              # グリッドに配置する要素のリスト
        ft.Container(
            content=ft.Text(
                f"項目 {i}",
                color=ft.Colors.BLUE_900,  # テキスト色を濃い青に
                weight=ft.FontWeight.BOLD,  # 太字に
                size=16,  # サイズを大きめに
            ),
            alignment=ft.alignment.center,
            bgcolor=ft.Colors.BLUE_100,
            border_radius=10,
            height=100,  # 高さを固定
        ) for i in range(1, 9)
    ],
)

GridViewの主なプロパティ

プロパティ名 説明
runs_count 行数(水平スクロール時)または列数(垂直スクロール時)
max_extent 各アイテムの最大幅/高さ
spacing グリッドアイテム間の主軸方向の間隔
run_spacing グリッドアイテム間の交差軸方向の間隔
child_aspect_ratio 子要素のアスペクト比(幅/高さ)
padding グリッド全体のパディング
expand 利用可能なスペースを埋めるかどうか(スクロールに影響)

適応型グリッドの例

ウィンドウサイズに応じて列数が自動調整されるグリッドの例です:

ft.GridView(
    runs_count=3,               # 列数を指定
    max_extent=200,             # 各アイテムの最大幅
    child_aspect_ratio=1.5,     # 子要素のアスペクト比(幅/高さ)
    spacing=15,
    run_spacing=15,
    controls=[
        ft.Container(
            content=ft.Column([
                ft.Icon(name=ft.Icons.FAVORITE, color=ft.Colors.RED),
                ft.Text(
                    f"カード {i}", 
                    color=ft.Colors.BROWN_900,  # 暗い茶色テキスト
                    weight=ft.FontWeight.BOLD,
                    size=16,
                ),
            ], alignment=ft.MainAxisAlignment.CENTER),
            alignment=ft.alignment.center,
            bgcolor=ft.Colors.AMBER_100,
            border_radius=10,
            border=ft.border.all(1, ft.Colors.AMBER_400),
        ) for i in range(1, 7)
    ],
)

2. Stack(重ね合わせレイアウト)

Stackは複数の要素を同じ空間に重ね合わせるレイアウトです。テキストを画像の上に配置したり、複雑なUIを構築したりするのに便利です。

基本的な使い方

ft.Stack([
    # 背景
    ft.Container(
        bgcolor=ft.Colors.BLUE_100,
        border_radius=10,
        width=300,
        height=200,
    ),
    # 中央のテキスト
    ft.Container(
        content=ft.Text(
            "中央のテキスト", 
            size=16,
            color=ft.Colors.BLUE_900,
            weight=ft.FontWeight.BOLD,
        ),
        alignment=ft.alignment.center,
        # テキスト背景を追加して視認性向上
        bgcolor="#DDFFFFFF",  # 半透明の白
        padding=8,
        border_radius=4,
    ),
    # 右下のアイコン
    ft.Container(
        content=ft.Icon(ft.Icons.STAR, color=ft.Colors.AMBER),
        alignment=ft.alignment.bottom_right,
        padding=10,
    ),
])

画像とテキストを重ねる例(視認性向上版)

よくあるヒーローセクションのようなUIを作成する際、テキストの視認性が課題になります。以下は視認性を向上させた実装例です:

ft.Stack([
    # 背景画像
    ft.Image(
        src="https://picsum.photos/350/220?random=3",
        width=350,
        height=220,
        fit=ft.ImageFit.COVER,
        border_radius=ft.border_radius.all(10),
    ),
    # 半透明のオーバーレイ(適度な透明度で画像も見えるように)
    ft.Container(
        bgcolor="#66000000",  # ARGB形式:66は透明度40%
        border_radius=10,
        width=350,
        height=220,
    ),
    # テキスト (視認性向上のため背景と境界線付き)
    ft.Container(
        content=ft.Text(
            "画像上のテキスト",
            color=ft.Colors.WHITE,
            size=22,
            weight=ft.FontWeight.BOLD,
        ),
        padding=15,
        bgcolor="#99000000",  # ARGB形式:99は透明度60%
        border=ft.border.all(2, ft.Colors.WHITE),  # 白い境界線を追加
        border_radius=5,
        alignment=ft.alignment.center,
    ),
])

視認性向上のための工夫

テクニック 詳細 Fletでの実装方法
半透明オーバーレイ 画像全体に薄い暗いオーバーレイを適用(40%程度) bgcolor="#66000000"
テキスト背景 テキスト自体にも半透明の背景を適用(60%程度) bgcolor="#99000000"
境界線 白い境界線でテキストコンテナを囲む border=ft.border.all(2, ft.Colors.WHITE)
適切なサイズ テキストサイズを十分に大きくする(20-22px程度) size=22, weight=ft.FontWeight.BOLD
パディング テキスト周りに十分な余白を確保 padding=15

3. Card(カードUI)

Cardはマテリアルデザインのカードコンポーネントで、関連するコンテンツをグループ化します。影やボーダーが付いた浮き上がったUIを簡単に作成できます。

基本的なカード

ft.Card(
    content=ft.Container(
        content=ft.Column([
            ft.Text("カードタイトル", weight=ft.FontWeight.BOLD),
            ft.Text("カードの説明文をここに入れます。"),
        ]),
        padding=15,
    ),
    width=300,
)

画像付きカード

ft.Card(
    content=ft.Column([
        ft.Image(
            src="https://picsum.photos/300/150?random=4",
            width=300,
            height=150,
            fit=ft.ImageFit.COVER,
        ),
        ft.Container(
            content=ft.Column([
                ft.Text("画像付きカード", weight=ft.FontWeight.BOLD, size=16),
                ft.Text("美しい画像とテキストを組み合わせたカードです。"),
                ft.Row([
                    ft.TextButton("詳細"),
                    ft.TextButton("共有"),
                ], alignment=ft.MainAxisAlignment.END),
            ]),
            padding=15,
        ),
    ]),
    width=300,
    elevation=5,  # 影の強さ
)

Cardの主なプロパティ

プロパティ名 説明
content カードの内容
elevation カードの影の強さ
color カードの背景色
margin カードの外側の余白
surface_tint_color カードの表面の色合い

4. レイアウトの組み合わせテクニック

これらのレイアウト要素を組み合わせることで、さらに洗練されたUIを作成できます。

GridView + Card + Stack の組み合わせ(視認性向上版)

以下は、GridViewの各セルにCardを配置し、さらにその中にStackを使って画像とテキストを重ねる高度な例です。テキストの視認性が向上するように実装しています:

ft.GridView(
    runs_count=2,  # 2列のグリッド
    max_extent=250,  # 各アイテムの幅を大きめに
    child_aspect_ratio=0.8,
    spacing=20,  # 間隔を広めに
    run_spacing=20,
    controls=[
        ft.Card(
            content=ft.Container(
                content=ft.Stack([
                    # 背景画像
                    ft.Image(
                        src=f"https://picsum.photos/250/300?random={i}",
                        width=250,
                        height=300,
                        fit=ft.ImageFit.COVER,
                    ),
                    # 上半分は透明、下半分だけ暗く
                    ft.Container(
                        bgcolor="#00000000",  # 完全透明
                        width=250,
                        height=150,
                    ),
                    ft.Container(
                        bgcolor="#99000000",  # 60%不透明
                        width=250,
                        height=150,
                        margin=ft.margin.only(top=150),  # 下半分に配置
                    ),
                    # テキスト要素
                    ft.Container(
                        content=ft.Column([
                            # タイトル用コンテナ
                            ft.Container(  
                                content=ft.Text(
                                    f"カード {i}",
                                    color=ft.Colors.WHITE,
                                    size=18,
                                    weight=ft.FontWeight.BOLD,
                                ),
                                bgcolor="#BF4336",  # 赤系の背景色(75%不透明)
                                padding=8,
                                border_radius=4,
                            ),
                            # 説明文用コンテナ
                            ft.Container(  
                                content=ft.Text(
                                    "サンプルテキスト",
                                    color=ft.Colors.WHITE,
                                    size=16,
                                ),
                                bgcolor="#BF0288D1",  # 青系の背景色(75%不透明)
                                padding=8,
                                border_radius=4,
                                margin=ft.margin.only(top=8),
                            ),
                            # アクションボタン
                            ft.Container(
                                content=ft.ElevatedButton(
                                    "詳細を見る",
                                    style=ft.ButtonStyle(
                                        color=ft.Colors.WHITE,
                                        bgcolor="#4CAF50",  # 緑系の背景色
                                    ),
                                ),
                                margin=ft.margin.only(top=15),
                            ),
                        ]),
                        padding=15,
                        alignment=ft.alignment.bottom_left,
                    ),
                ]),
                width=250,
                height=300,
            ),
            elevation=5,
        ) for i in range(1, 5)
    ],
    expand=False,  # 高さを固定しない(スクロールのため)
)

レイアウト組み合わせでの視認性向上ポイント

テクニック 詳細 効果
グラデーション効果の代替 下半分だけ暗くし、上部は透明に設定 上部は画像がはっきり見え、下部はテキストが読みやすくなる
コントラストの高い背景色 テキスト背景に目立つ色を使用し、適度な透明度を設定 背景画像との調和を保ちながらテキストを強調できる
境界とパディング 要素間に適切な余白を設け、テキストコンテナに角丸を適用 視覚的に要素を分離し、読みやすさが向上する
サイズの最適化 グリッドアイテム、テキスト、ボタンのサイズを十分に大きく設定 視認性が高まり、タッチ操作も容易になる

サンプルコード

以下のコードで、この記事で紹介したすべてのレイアウト要素を1つのアプリケーションで試すことができます。特に視認性を重視した実装になっています:

import flet as ft

def main(page: ft.Page):
    page.title = "Flet 高度なレイアウト(視認性向上版)"
    page.bgcolor = ft.Colors.BLACK
    page.padding = 20
    
    # ページ全体をスクロール可能に設定
    page.scroll = "auto"
    
    # ----- 1. GridView -----
    page.add(
        ft.Text("1. GridView (グリッドレイアウト)", size=20, weight=ft.FontWeight.BOLD, color=ft.Colors.WHITE),
        ft.Text("固定数グリッド:", color=ft.Colors.WHITE),
        
        ft.GridView(
            runs_count=4,
            max_extent=150,
            child_aspect_ratio=1.0,
            spacing=15,
            run_spacing=15,
            controls=[
                ft.Container(
                    content=ft.Text(
                        f"項目 {i}",
                        color=ft.Colors.BLUE_900,
                        weight=ft.FontWeight.BOLD,
                        size=16,
                    ),
                    alignment=ft.alignment.center,
                    bgcolor=ft.Colors.BLUE_100,
                    border_radius=10,
                    height=100,
                ) for i in range(1, 9)
            ],
            expand=False,
        ),
        
        ft.Container(padding=25),
        ft.Text("適応型グリッド:", color=ft.Colors.WHITE),
        
        ft.GridView(
            runs_count=3,
            max_extent=200,
            child_aspect_ratio=1.5,
            spacing=15,
            run_spacing=15,
            controls=[
                ft.Container(
                    content=ft.Column([
                        ft.Icon(name=ft.Icons.FAVORITE, color=ft.Colors.RED),
                        ft.Text(
                            f"カード {i}", 
                            color=ft.Colors.BROWN_900,
                            weight=ft.FontWeight.BOLD,
                            size=16,
                        ),
                    ], alignment=ft.MainAxisAlignment.CENTER),
                    alignment=ft.alignment.center,
                    bgcolor=ft.Colors.AMBER_100,
                    border_radius=10,
                    border=ft.border.all(1, ft.Colors.AMBER_400),
                ) for i in range(1, 7)
            ],
            expand=False,
        ),
    )
    
    # ----- 2. Stack -----
    page.add(
        ft.Container(padding=30),
        ft.Text("2. Stack (重ね合わせレイアウト)", size=20, weight=ft.FontWeight.BOLD, color=ft.Colors.WHITE),
        ft.Text("基本的なStack:", color=ft.Colors.WHITE),
        
        ft.Container(
            width=300,
            height=200,
            content=ft.Stack([
                # 背景
                ft.Container(
                    bgcolor=ft.Colors.BLUE_100,
                    border_radius=10,
                    width=300,
                    height=200,
                ),
                # 中央のテキスト
                ft.Container(
                    content=ft.Text(
                        "中央のテキスト", 
                        size=16,
                        color=ft.Colors.BLUE_900,
                        weight=ft.FontWeight.BOLD,
                    ),
                    alignment=ft.alignment.center,
                    bgcolor="#DDFFFFFF",
                    padding=8,
                    border_radius=4,
                ),
                # 右下のアイコン
                ft.Container(
                    content=ft.Icon(ft.Icons.STAR, color=ft.Colors.AMBER),
                    alignment=ft.alignment.bottom_right,
                    padding=10,
                ),
            ]),
        ),
        
        ft.Container(padding=15),
        ft.Text("画像と重ねるStack (改善版):", color=ft.Colors.WHITE),
        
        ft.Container(
            width=350,
            height=220,
            content=ft.Stack([
                # 背景画像
                ft.Image(
                    src="https://picsum.photos/350/220?random=3",
                    width=350,
                    height=220,
                    fit=ft.ImageFit.COVER,
                    border_radius=ft.border_radius.all(10),
                ),
                # 半透明のオーバーレイ
                ft.Container(
                    bgcolor="#66000000",
                    border_radius=10,
                    width=350,
                    height=220,
                ),
                # テキスト
                ft.Container(
                    content=ft.Text(
                        "画像上のテキスト",
                        color=ft.Colors.WHITE,
                        size=22,
                        weight=ft.FontWeight.BOLD,
                    ),
                    padding=15,
                    bgcolor="#99000000",
                    border=ft.border.all(2, ft.Colors.WHITE),
                    border_radius=5,
                    alignment=ft.alignment.center,
                ),
            ]),
        ),
    )
    
    # ----- 3. Card -----
    page.add(
        ft.Container(padding=30),
        ft.Text("3. Card (カードUI)", size=20, weight=ft.FontWeight.BOLD, color=ft.Colors.WHITE),
        ft.Text("基本的なCard:", color=ft.Colors.WHITE),
        
        ft.Card(
            content=ft.Container(
                content=ft.Column([
                    ft.Text("カードタイトル", weight=ft.FontWeight.BOLD),
                    ft.Text("カードの説明文をここに入れます。"),
                ]),
                padding=15,
            ),
            width=300,
        ),
        
        ft.Container(padding=15),
        ft.Text("画像付きCard:", color=ft.Colors.WHITE),
        
        ft.Card(
            content=ft.Column([
                ft.Image(
                    src="https://picsum.photos/300/150?random=4",
                    width=300,
                    height=150,
                    fit=ft.ImageFit.COVER,
                ),
                ft.Container(
                    content=ft.Column([
                        ft.Text("画像付きカード", weight=ft.FontWeight.BOLD, size=16),
                        ft.Text("美しい画像とテキストを組み合わせたカードです。"),
                        ft.Row([
                            ft.TextButton("詳細"),
                            ft.TextButton("共有"),
                        ], alignment=ft.MainAxisAlignment.END),
                    ]),
                    padding=15,
                ),
            ]),
            width=300,
            elevation=5,
        ),
    )
    
    # ----- 4. レイアウトの組み合わせ -----
    page.add(
        ft.Container(padding=30),
        ft.Text("4. レイアウトの組み合わせテクニック (視認性向上版)", size=20, weight=ft.FontWeight.BOLD, color=ft.Colors.WHITE),
        ft.Text("GridView + Card + Stack:", color=ft.Colors.WHITE),
        
        ft.Container(
            content=ft.GridView(
                runs_count=2,
                max_extent=250,
                child_aspect_ratio=0.8,
                spacing=20,
                run_spacing=20,
                controls=[
                    ft.Card(
                        content=ft.Container(
                            content=ft.Stack([
                                # 背景画像
                                ft.Image(
                                    src=f"https://picsum.photos/250/300?random={i}",
                                    width=250,
                                    height=300,
                                    fit=ft.ImageFit.COVER,
                                ),
                                # 下半分だけ暗くする
                                ft.Container(
                                    bgcolor="#00000000",
                                    width=250,
                                    height=150,
                                ),
                                ft.Container(
                                    bgcolor="#99000000",
                                    width=250,
                                    height=150,
                                    margin=ft.margin.only(top=150),
                                ),
                                # テキスト
                                ft.Container(
                                    content=ft.Column([
                                        # タイトル用コンテナ
                                        ft.Container(  
                                            content=ft.Text(
                                                f"カード {i}",
                                                color=ft.Colors.WHITE,
                                                size=18,
                                                weight=ft.FontWeight.BOLD,
                                            ),
                                            bgcolor="#BF4336",
                                            padding=8,
                                            border_radius=4,
                                        ),
                                        # 説明文用コンテナ
                                        ft.Container(  
                                            content=ft.Text(
                                                "サンプルテキスト",
                                                color=ft.Colors.WHITE,
                                                size=16,
                                            ),
                                            bgcolor="#BF0288D1",
                                            padding=8,
                                            border_radius=4,
                                            margin=ft.margin.only(top=8),
                                        ),
                                        # アクションボタン
                                        ft.Container(
                                            content=ft.ElevatedButton(
                                                "詳細を見る",
                                                style=ft.ButtonStyle(
                                                    color=ft.Colors.WHITE,
                                                    bgcolor="#4CAF50",
                                                ),
                                            ),
                                            margin=ft.margin.only(top=15),
                                        ),
                                    ]),
                                    padding=15,
                                    alignment=ft.alignment.bottom_left,
                                ),
                            ]),
                            padding=0,
                            width=250,
                            height=300,
                        ),
                        elevation=5,
                    ) for i in range(1, 5)
                ],
                expand=False,
            ),
        ),
    )

ft.app(target=main)

まとめ

image.png

Fletを使用すれば、Pythonだけで視認性の高い美しいUIを持つアプリケーションを構築できます。本記事で紹介したGridView、Stack、Cardの活用方法と視認性向上テクニックを習得することで、プロフェッショナルな見た目のアプリケーションが簡単に作成できるようになります。

特に画像上のテキスト表示など、視認性が問題になりやすい部分でも、適切なオーバーレイやコントラストの高い背景色、境界線などを活用することで、読みやすいUIが実現できます。

ぜひこれらのテクニックを活用して、あなたのFletアプリケーションをさらに魅力的なものにしてください!

免責事項

本記事の作成にあたり、文章や図解の生成にClaude Sonnet, Napkin AIを、ファクトチェックにGensparkを活用しました。最終的な編集と確認は筆者が行っています。

0
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?