1
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?

More than 1 year has passed since last update.

fletでドロップダウンコンテナを作ってみた

Last updated at Posted at 2023-05-11

投稿時点で、fletにはアコーディオン的な、折り畳みが可能なWidget(control)がなかったので、
flutterでいうところのExpansionTileを作ってみた。

dropdownContainer.py
from typing import List, Optional
from flet import *
from flet_core.control import Control, OptionalNumber
from flet_core.types import AnimationValue,BorderRadiusValue,MarginValue,PaddingValue

class DropDownContainer(UserControl):
    def __init__(
            self,
            leading:Optional[Control] = None,
            title:Optional[Control] = None,
            inner_contents:Optional[List[Control]] = None,
            inner_content_height:OptionalNumber = 25,
            action_button_icon:Optional[str] = icons.ARROW_DROP_DOWN_CIRCLE_ROUNDED,
            action_button_icon_size:OptionalNumber = 20,
            height:OptionalNumber = 70,
            width:OptionalNumber = 265,
            padding: PaddingValue = None,
            margin: MarginValue = None,
            bgcolor: Optional[str] = None,
            border: Optional[Border] = None,
            border_radius: BorderRadiusValue = None,
            animate: AnimationValue = animation.Animation(400,"decelerate"),
            disabled: Optional[bool] = None,
            clip_behavior: Optional[ClipBehavior] = ClipBehavior.HARD_EDGE):
        self.leading = leading
        self.title = title
        self.inner_contents = inner_contents
        self.inner_content_height = inner_content_height
        self.inner_contents_height = len(self.inner_contents) * self.inner_content_height
        self.action_button_icon = action_button_icon
        self.action_button_icon_size = action_button_icon_size
        
        self.dd_height = height
        self.dd_width = width
        self.dd_padding = padding
        self.dd_margin = margin
        self.dd_bgcolor = bgcolor
        self.dd_border = border
        self.dd_border_radius = border_radius
        self.dd_animate = animate
        self.dd_disabled = disabled
        self.dd_clip_behavior = clip_behavior
        self.full_width = (width+padding.left+padding.right) if padding is not None else width
        self.full_height = (height+padding.top+padding.bottom) if padding is not None else height
        super().__init__()
        

    def ExpandContainer(self,e):
        openHeight = self.full_height + self.inner_contents_height

        if self.controls[0].height != openHeight:
            self.controls[0].height = openHeight
            self.controls[0].update()
        else:
            self.controls[0].height = self.full_height
            self.controls[0].update()


    def TitleContainer(self):
        return Container(
            width=self.dd_width,
            height=self.dd_height,
            content=Row(
                alignment=MainAxisAlignment.SPACE_BETWEEN,
                vertical_alignment=CrossAxisAlignment.CENTER,
                controls=[
                    self.leading,
                    self.title,
                    IconButton(
                        icon=self.action_button_icon,
                        icon_size=self.action_button_icon_size,
                        on_click=lambda e:self.ExpandContainer(e),
                    )
                ]
            )
        )
    
    def InnerContainer(self):
        return Container(
            width=self.dd_width,
            height=self.inner_contents_height,
            content=Column(
                alignment=MainAxisAlignment.START,
                spacing=0,
                controls=self.inner_contents
            )

        )
    
    def build(self):
        return Container(
            width = self.full_width,
            height = self.full_height,
            bgcolor = self.dd_bgcolor,
            border = self.dd_border,
            border_radius = self.dd_border_radius,
            animate = self.dd_animate,
            disabled = self.disabled,
            padding = self.dd_padding,
            clip_behavior = self.dd_clip_behavior,
            content=Column(
                spacing=0,
                alignment=MainAxisAlignment.START,
                horizontal_alignment=CrossAxisAlignment.CENTER,
                controls=[
                    self.TitleContainer(),
                    self.InnerContainer(),
                ]
            )
        )

使用例

myDropdownContainer.py
from flet import *
from dropDownContainer import DropDownContainer

def myDropDownContainer(title:str,sub_title:str = None,inner_contents:list =[]):
    def _getInnerData(inner_contents):
        l = []

        for item in inner_contents:
            l.append(
                Container(
                    padding=padding.only(left=20),
                    content=Row(
                        height=25,
                        spacing=0,
                        controls=[
                            Container(
                                padding=padding.only(right=10),
                                content=Icon(icons.FOLDER,size=14),
                            ),
                            Text(item,size=9,weight="bold",color="white54")
                        ]
                    )
                )
            )
        
        return l
    
    sub_title_widget = Text(sub_title,size=9,color="white54")

    title_container = Container(
            height=70,
            content=Column(
                spacing=1,
                alignment=MainAxisAlignment.CENTER,
                controls=[
                    Text(title,size=11),
                ]
            )
        )
    if sub_title is not None :
        title_container.content.controls.append(sub_title_widget)
    
    return DropDownContainer(
        leading=Icon(icons.FOLDER),
        title=title_container,
        inner_contents=_getInnerData(inner_contents),
        inner_content_height=25,
        bgcolor="white54",
        border_radius=11,
        height=70,
        width=265,
        padding=padding.only(left=10,right=10),
    )
main.py
import flet
from flet import *

from myDropDownContainer import myDropDownContainer

def main(page:Page):
    page.title = 'expandingcontainer'
    main_container = Container(
        width=400,
        height=600,
        padding=20,
        content = Column(
            scroll="hidden",
            controls=[
                myDropDownContainer(
                    title='MyDropDownContainer',
                    sub_title="doropdown_container",
                    inner_contents=["hoge_folder1","hoge_folder2","hoge_folder3"]
                    ),
                myDropDownContainer(
                    title='MyDropDownContainer',
                    inner_contents=["hoge_folder1","hoge_folder2","hoge_folder3"]
                    ),
            ]
        )
    )
    page.add(main_container)
    page.update()

if __name__ == '__main__':
    flet.app(target=main)

大満足です!

1
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
1
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?