Controles de Layout
Card, Tabs, SafeArea, Divider, VerticalDivider, ExpansionPanelList são outros controles que facilitam a divisão, exibição ou ocultação de conteúdo dentro de uma página de aplicativo.
Seguem-se alguns exemplos de códigos usando esses controles.
Exemplo de uso de Card
Leia sobre a descrição do controle, suas propriedades e evento em Controles de Layout: Card.
O código abaixo exibe a construção de uma página com 3 cards.
import flet as ft def main(page): page.title = "Exemplo usando \"card\"" listitulo = ft.ListTile(leading=ft.Icon(ft.icons.ACCESS_ALARM, size=50, color="#D3143E"), title=ft.Text("Compromisso: 28 de junho de 2024"), subtitle=ft.Text("Aniversário de seu filho. Não esqueça o presente!"),) def apagar(e): listitulo.title= ft.Text("") listitulo.subtitle=ft.Text("* apagado", color="#aaaaaa") cartao.color="WHITE" page.update() def proximo(e): listitulo.title=ft.Text("Compromisso: 01 de agosto de 2024") listitulo.subtitle=ft.Text("Viagem para São Paulo", color="#000000") cartao.color="#CBEBA8" page.update() bt1 = ft.TextButton("Apagar", on_click=apagar) bt2 = ft.TextButton("Próximo compromisso", on_click=proximo) linha = ft.Row([bt1, bt2], alignment=ft.MainAxisAlignment.END) coluna = ft.Column([listitulo, linha,]) contem = ft.Container(coluna, width=500, padding=20,) cartao = ft.Card(contem, color="YELLOW", shadow_color="white", elevation=8.0) page.add(cartao) ft.app(target=main)
Na figura 1 o resultado desse código, quando executado.
Tabs
Leia sobre a descrição do controle, suas propriedades e evento em Controle Tabs.
O controle Tabs, usualmente chamado de guias ou abas em português, é usado para separar conteúdo de categorias diferentes, facilitando a navegação do usuário. Ele simula a marcação de bookmarks em um livro físico, para indicar setores de conteúdos diversos, sendo um padrão de desenho com o qual os usuários estão acostumados, no desktop ou web.
Exemplo de uso de Tabs
O código abaixo exibe a construção de uma página o uso de Tabs.
import flet as ft def main(page: ft.Page): page.bgcolor=ft.colors.BROWN_200 ct_interno=ft.Container(content=ft.Text("Conteúdo do Tab 1 dentro de um Card", size=20, weight=ft.FontWeight.BOLD), padding=45) card = ft.Card(content= ct_interno, elevation=20, expand=1) ct_tab1 = ft.Container(content=card, bgcolor="#BAE3ED", alignment=ft.alignment.center) tab1 = ft.Tab(text="Tab 1", content=ct_tab1) ct_tab2 = ft.Container(content=ft.Text("Conteúdo de texto do Tab 2", size=30), bgcolor="#BBF3EF", margin = ft.margin.all(10.0), padding=ft.padding.all(1.0), alignment=ft.alignment.top_right, border=ft.border.all(2, "#55555"), border_radius=20) tab2 = ft.Tab(text="Tab 2", icon=ft.icons.SEARCH, content=ct_tab2) ct_tab3 = ft.Container(content=ft.Text("Conteúdo de texto do Tab 3", size=30), bgcolor="#FCF5CC", alignment=ft.alignment.bottom_left) tab3 = ft.Tab(text="Tab 3", icon=ft.icons.SETTINGS, content=ct_tab3) tabs = ft.Tabs(tabs=[tab1, tab2, tab3], selected_index=0, divider_color="#ABCAD0", label_color="WHITE", unselected_label_color="BLACK", overlay_color = "YELLOW", indicator_padding=10, indicator_color="RED") page.add(ft.Container(tabs, bgcolor=ft.colors.BROWN_200, expand=1)) ft.app(target=main)
O resultado desse código está mostrado na figura 2.
O primeiro tab exibe um card com texto interno, centralizado. O segundo tab tem um container formatado com bordas arredondadas e texto no alto, à direita. O terceiro tab tem texto em baixo, à esquerda.
Observe que no código acima, e na maioria dos blocos de código nessas notas, os controles são montados por partes, separando controles que serão depois inseridos dentro de outros. Para montar o tab1, criamos ct_interno, um container com um texto e o inserimos dentro de card, que é inserido em ct_tab1 e finalmente em tab1. Isso é feito por motívo didático, para que o código fique mais fácil de ser entendido, e não tem efeito no resultado no momento da execução. Esse estilo é uma preferência do programador. Uma forma alternativa para a construção do mesmo controle pode ser vista abaixo.
tab1 = ft.Tab( text="Tab 1", content=ft.Container( content=ft.Card( content=ft.Container( content=ft.Text("Conteúdo do Tab 1 dentro de um Card", size=20, weight=ft.FontWeight.BOLD), padding=45 ), elevation=20, expand=1 ), bgcolor="#BAE3ED", alignment=ft.alignment.center ) )
De qualquer forma é importante estabelecer um critério de indentação e se manter coerente com ele.
SafeArea
SafeArea insere conteúdo com preenchimento (padding, as distâncias entre as margens internas do container com as bordas externas do controle) de modo a impedir que os elementos de interface do sistema operacional se sobreponham às do aplicativo. Leia sobre a descrição do controle, suas propriedades em Controles de Layout: SafeAreaCard.
Um exemplo é mostrado no código abaixo.
import flet as ft class Contador: contagem = 0 def main(page: ft.Page): def add_click(e): cliques.contagem += 1 contador.value = f"Contador: {cliques.contagem}" contador.update() page.horizontal_alignment=ft.CrossAxisAlignment.CENTER page.vertical_alignment=ft.MainAxisAlignment.CENTER page.floating_action_button = ft.FloatingActionButton(icon=ft.icons.ADD, on_click=add_click) cliques = Contador() contador = ft.Text("Contador: 0", size=30, color="WHITE", weight=ft.FontWeight.BOLD) page.add( ft.SafeArea( expand=False, content=ft.Container( content=contador, padding=35, width=300, height=190, alignment=ft.alignment.center, bgcolor="BLUE", gradient=ft.LinearGradient(colors=[ft.colors.BLACK, ft.colors.BLUE_900]), border=ft.border.all(3, ft.colors.BLUE_100), border_radius=ft.border_radius.all(10) ) ) ) ft.app(main)
A execução desse código gera um aplicativo mostrado na figura 3.
Observe que, para manter um contador global foi criada a classe e propriedade State.counter
. O objeto cliques = Contador()
tem, portanto a propriedade cliques.contagem
, que é incrementada a cada clique no botão floating_action_button
.
Divider e VerticalDivider
São controles usados para desenhar uma linha divisória, horizontal e vertical, respectivamente. Leia sobre a descrição dos controles e suas propriedades em Controle Divider e VerticalDivider.
import flet as ft def main(page: ft.Page): ct1 = ft.Container(bgcolor="#797EF6", expand=True) ct2 = ft.Container(bgcolor="#4ADEDE", expand=True) divisorVertical = ft.VerticalDivider(width=50, thickness=10, color="#960cc9") ct3 = ft.Container(bgcolor="#1AA7EC", expand=True) ct4 = ft.Container(bgcolor="#1E2F97", expand=True) divisorHorizontal= ft.Divider(height=50, thickness=40, color="#F6E750") page.add( ft.Row([ct1, divisorVertical, ct2], spacing=0, expand=True), ft.Column([ct3, divisorHorizontal, ct4], spacing=0, expand=True) ) ft.app(target=main)
O código executado é renderizado como a figura 4.
A única diferença entre propriedades de Divider e VerticalDivider são as propriedades Divider.height
e VerticalDivider.width
.
ExpansionPanel e ExpansionPanelList
ExpansionPanelList é o controle usado para criar painéis expansíveis, que podem ser contraídos até um mínimo, expandidos para exibir conteúdo, ou removidos da página. ExpansionPanelsList recebe uma lista de controles ExpansionPanel. Leia sobre a descrição dos controles e suas propriedades em Controle ExpansionPanelList e ExpansionPanel.
import flet as ft class Painel(ft.ExpansionPanel): def __init__(self, cabecalho, titulo, texto, cor, botao=None, indice=0): super().__init__() self.can_tap_header=True self.bgcolor=cor self.header=ft.Text(" " + cabecalho, size=22, weight=ft.FontWeight.BOLD) self.titulo=ft.Text(titulo, size=18) self.texto=ft.Text(texto, size=17) self.conteudo=ft.ListTile( title=self.titulo, subtitle=self.texto, trailing=botao ) self.content=self.conteudo self.indice = indice def main(page: ft.Page): cor = [ft.colors.GREEN_100, ft.colors.BLUE_100, ft.colors.RED_100, ft.colors.WHITE10, ft.colors.BLUE_500, ft.colors.WHITE70] def pegar_painel(index): for pn in panel.controls: if index == pn.indice: return pn return None def mudou(e: ft.ControlEvent): if int(e.data)==4: return atividade.conteudo.subtitle.value += f"\nO painel {e.data} foi modificado" page.update() def apagar(e: ft.ControlEvent): pn = pegar_painel(e.control.data) if pn: panel.controls.remove(pn) atividade.conteudo.subtitle.value += f"\nFoi apagado o Painel {e.control.data}" page.update() panel = ft.ExpansionPanelList( elevation=8, spacing=6, expand_icon_color=ft.colors.AMBER_100, divider_color=ft.colors.CYAN_ACCENT_100, on_change=mudou ) panel.controls.append( Painel("Atividades Online", "Lista das ações realizadas no aplicativo.", "", cor[4], None,0 ) ) panel.controls.append( Painel( "Painel 1", "Conteúdo do painel 1", "Clique no ícone para apagar o painel 1.", cor[0], ft.ElevatedButton("Apagar", icon=ft.icons.DELETE, width=150, height=30, data=1, on_click=apagar), 1 ) ) panel.controls.append( Painel( "Painel 2", "Conteúdo do painel 2", "Clique no ícone para apagar o painel 2.", cor[1], ft.ElevatedButton("Apagar", icon=ft.icons.DELETE, width=150, height=30, data=2, on_click=apagar), 2 ) ) panel.controls.append( Painel( "Painel 3", "Conteúdo do painel 3", "Clique no ícone para apagar o painel 3.", cor[2], ft.ElevatedButton("Apagar", icon=ft.icons.DELETE, width=150, height=30, data=3, on_click=apagar), 3 ) ) atividade = Painel("Resumo de Atividades", "", "Conteúdo de texto da informação de uso", cor[5]) panel.controls.append(atividade) page.add(panel) ft.app(target=main)
O resultado pode ser visto na figura 5.
Como são gerados no código vários painéis flet.ExpansionPanel é interessante criar a classe Class Painel
que herda de ExpansionPanel, personalizando na inicialização cada caso a ser inserido. O último dos painéis exibidos, atividade é usado para armazenar e exibir as ações feitas no aplicativo, no campo atividade.conteudo.subtitle.value. Essas ações são executadas nos eventos ExpansionPanelList.on_change e pelo clique nos botões ElevatedButton colocados em cada painel, exceto o último, e pela ação de apagar um painel. Os painéis são identificados pela propriedade painel.indice, usada para encontrar e deletar um deles.
Muito bom esse site. Já está nos meus favoritos!
Obrigado André. Me ajude a divulgar!