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でグリッドビューとリストビューの切り替えボタンの実装について

Posted at

1.はじめに

本記事はFletで提供されているUI

  • GridView
  • ListView

を交互に切り替えるSwitchを実装したのでその備忘録です。
(※表示したいリストの数が5000件ぐらいなどの場合は分割して表示、無限リロードのような実装を行う必要があります。単純に読み込みが遅くなるので。)

実行環境は

  • Python : 3.13.1
  • Flet : 0.25.2

2.コンポーネントの説明

class My_View(Column):
    def __init__(self, view_items: list):
        super().__init__()
        self.view_items = view_items
        # 初期表示はグリッドビューとしています
        self.my_switch = Switch(
            label='Grid View',
            label_style=TextStyle(letter_spacing=0.5, size=16,),
            value=True,
            on_change=self.switch_changed,
            height=25,
            active_track_color=Colors.LIGHT_BLUE,
            inactive_track_color=Colors.DEEP_ORANGE,
            thumb_icon=ControlState.SELECTED,
        )
        self.my_grid = GridView(
            expand=True,
            max_extent=200,
            child_aspect_ratio=1.0,
        )
        self.my_list = ListView(
            expand=True,
            spacing=10,
            visible=False,
        )
        self.controls = [
            self.my_switch,
            self.my_grid,
            self.my_list,
        ]

    def before_update(self):
        # コンポーネントの更新が行われる前に、毎回以下のコードが実行される。
        # 無限リロードを実装する場合は、ビューのロードと表示の切り替えはそれぞれ別関数で実装する必要あり。
        self.my_grid.controls.clear()
        self.my_list.controls.clear()
        for item in self.view_items:
            self.__my_container = Container(
                content=Text(item, color=Colors.BLACK, no_wrap=False),
                alignment=alignment.center,
                bgcolor=Colors.AMBER_100,
                border=border.all(1, Colors.AMBER_400),
                border_radius=border_radius.all(10),
                padding=padding.all(10),
            )
            if self.my_switch.value:
                self.my_grid.visible = True
                self.my_list.visible = False
                self.my_grid.controls.append(self.__my_container)
            else:
                self.my_grid.visible = False
                self.my_list.visible = True
                self.my_list.controls.append(self.__my_container)

    def switch_changed(self, e):
        self.my_switch.label = 'Grid View' if e.control.value else 'List View'
        self.update()

上記実装のポイント:

  • GridViewListView自体はともにcontrolsに追加している(アイテムが空の状態)
  • 表示しないViewについてはvisible=Falseとする
  • Viewに追加しているContainerは共通のものを使用しているが、別個で実装も可能
  • Switchボタンをクリックしたときのイベントはvalue=True/Falselabelの切り替え、Viewの更新
  • before_updateに記載されたコードは更新が走るたびに、実行される(現実装ではView内に追加されたアイテムは毎回クリアしてから、SwitchのオンオフでViewにアイテムを追加している。)

3.作成物

今回作成したコードをテストデータとともに表示させるコードが以下:

import flet as ft
from flet import (
    alignment,
    border,
    border_radius,
    Column,
    Colors,
    Container,
    ControlState,
    GridView,
    ListView,
    padding,
    Page,
    ScrollMode,
    Switch,
    Text,
    TextStyle,
)

class My_View(Column):
    def __init__(self, view_items: list):
        super().__init__()
        self.view_items = view_items
        # 初期表示はグリッドビューとしています
        self.my_switch = Switch(
            label='Grid View',
            label_style=TextStyle(letter_spacing=0.5, size=16,),
            value=True,
            on_change=self.switch_changed,
            height=25,
            active_track_color=Colors.LIGHT_BLUE,
            inactive_track_color=Colors.DEEP_ORANGE,
            thumb_icon=ControlState.SELECTED,
        )
        self.my_grid = GridView(
            expand=True,
            max_extent=200,
            child_aspect_ratio=1.0,
        )
        self.my_list = ListView(
            expand=True,
            spacing=10,
            visible=False,
        )
        self.controls = [
            self.my_switch,
            self.my_grid,
            self.my_list,
        ]

    def before_update(self):
        # コンポーネントの更新が行われる前に、毎回以下のコードが実行される。
        # 無限リロードを実装する場合は、ビューのロードと表示の切り替えはそれぞれ別関数で実装する必要あり。
        self.my_grid.controls.clear()
        self.my_list.controls.clear()
        for item in self.view_items:
            self.__my_container = Container(
                content=Text(item, color=Colors.BLACK, no_wrap=False),
                alignment=alignment.center,
                bgcolor=Colors.AMBER_100,
                border=border.all(1, Colors.AMBER_400),
                border_radius=border_radius.all(10),
                padding=padding.all(10),
            )
            if self.my_switch.value:
                self.my_grid.visible = True
                self.my_list.visible = False
                self.my_grid.controls.append(self.__my_container)
            else:
                self.my_grid.visible = False
                self.my_list.visible = True
                self.my_list.controls.append(self.__my_container)

    def switch_changed(self, e):
        self.my_switch.label = 'Grid View' if e.control.value else 'List View'
        self.update()


def main(page: Page):
    # アプリケーション上でスクロールができるように設定
    page.scroll = ScrollMode.ADAPTIVE
    # テストデータ
    my_items = [f'item {i}' for i in range(101)]
    # コンポーネントをページに追加
    page.add(My_View(my_items))


ft.app(main)

上記コードを実行すると、以下のようなグリッド表示とリスト表示となります。

スクリーンショット 2025-01-19 161957.png

スクリーンショット 2025-01-19 162020.png

4.最後に

少々課題が残っていますが、よくあるグリッドからリスト(またはその逆)への表示切替を実装することができました。(件数が膨大な場合は200件ずつなどの塊ごとに表示させるなど工夫の余地あり。)

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?