
Outro controle de Layout
Controle Dismissible
Dismissible é um controle que pode ser arrastado em uma direção especificada. Quando arrastado ele gera eventos que podem ser capturados para efetuar ações sobre o aplicativo. O conteúdo desenhado dentro do controle permanece visível e acompanha o arrasto do controle que o contém. O controle é dispensado (eliminado) do aplicativo quando atinge um deslocamento mínimo determinado em código.

Nota: chamaremos de dispensa a ação de dismiss do controle. Antes da dispensa o controle encolhe em tamanho, gerando os eventos descritos abaixo.
Um exemplo bem reduzido de uso do dismiss é mostrado abaixo.
import flet as ft
import copy
def main(page):
dm1=ft.Dismissible(content=ft.Text("Primeira Linha", size=20, bgcolor=ft.colors.AMBER_100))
(dm2 := copy.deepcopy(dm1)).content.value="Segunda Linha"
(dm3 := copy.deepcopy(dm1)).content.value="Terceira Linha"
page.add(ft.Column([dm1, dm2, dm3]))
ft.app(main)
Esse código gera o seguinte aplicativo, mostrado na figura 1 em três estados:

Nesse exemplo criamos um controle dm1=ft.Dismissible() e o copiamos, usando deepcopy para dois outros controles. O método copy.deepcopy é necessário para que controles internos sejam copiados e a cópia seja feita por valor. Isso significa que dm2 e dm3 são novos objetos e não apenas uma nova referência para dm1. Com isso podemos mudar dm2.content.value="Segunda Linha" (o valor do conteúdo interno).
Nota: O operador walrus (:=) de atribuição tem o efeito de fazer uma atribuição e já retornar o objeto para operações posteriores. Portanto:
(dm2 := copy.deepcopy(dm1)).content.value="Segunda Linha"
# é o mesmo que
dm2 = copy.deepcopy(dm1)
dm2.content.value="Segunda Linha"
Em um caso mais elaborado podemos inserir linhas formatadas (por exemplo inserindo o texto dentro de containers), capturar outros eventos e definir outras propriedades. A figura 2 mostra um caso um pouco mais elaborado e o exemplo de uso de Dismissible no final desse texto mostra um código mais completo.

Propriedades de Dismissible
Dismissible tem as seguintes propriedades:
| Propriedade | Descrição |
|---|---|
| background | um controle que fica por trás do controle principal que exibe conteúdo. Se secondary_background também for especificado esse controle secundário aparece como fundo quando o conteúdo é arrastado para os lados ou verticalmente. |
| content | um controle filho que fica exibido dentro do Dismissible e se move com ele. |
| cross_axis_end_offset | especifica um valor para deslocamento vertical quando o controle é movido horizontalmente, fazendo o controle se mover na diagonal, para baixo se o valor for positivo, para cima se negativo. |
| direction | direção usada para dispensar o controle. Os valores possível estão no enum DismissDirection:
|
| dismiss_thresholds | o valor mínimo de deslocamento considerado para dispensar o controle. A partir desse valor o controle é removido do aplicativo. Por exemplo, se o valor é de 0.4 (o default) a barra tem que ser movida de 40% ou mais de sua extensão para ser dispensada. Seu valor é especificado como um dicionário tendo como chaves um objeto DismissDirection e o valor um valor numérico entre 0.0 e 1.0. O bloco de código mostra isso:
ft.Dismissible(
# ...
dismiss_thresholds={
ft.DismissDirection.VERTICAL: 0.1,
ft.DismissDirection.START_TO_END: 0.7
}
)
Esse dicionário define que os valores mínimos (thresholds) são 10% na vertical e 70% na horizontal, se o movimento for do início para o final (para a direita). |
| movement_duration | a duração do movimento para que o controle seja dispensado ou retorne para sua posição original. |
| resize_duration | a duração do movimento de contração antes que o evento de dispensa seja acionado. |
| secondary_background | um controle desenhado por tras do conteúdo principal, que é exposto quando o conteúdo é arrastado para os lados. Só pode ser especificado se o background também for definido. |

Eventos de Dismissible
| Evento | Descrição |
|---|---|
| on_confirm_dismiss | um evento que ocorre antes que o controle seja dispensado, dando a oportunidade de se confirmar ou negar essa operação. O controle não pode ser arrastado novamente até que essa pendência seja resolvida.
Para resolver essa pendência deve ser chamado o método confirm_dismiss(dismiss) passando um booleano: True para confirmar, provocando a dispensa do controle, False para negar, o que faz com que ele volte para sua posição original. Uma possibilidade consiste em apresentar a pergunta em uma caixa como AlertDialog. |
| on_dismiss | dispara quando o controle é dispensado. Antes da dispensa o controle é contraído, diminuindo de tamanho. |
| on_resize | dispara quando o controle muda de tamanho, o que ocorre, por exemplo, na contração ao ser dispensado. |
| on_update | dispara quando o controle é arrastado, independentemente de ser ou não dispensado. |
Método de Dismissible
| Método | Descrição |
|---|---|
| confirm_dismiss(dismiss: bool) | resolve a pendência quando a dispensa é requerida. Esse evento pode ser chamado quando se trata do evento on_confirm_dismiss. |

Exemplo de uso de Dismissible
Um exemplo mais completo de código está listado abaixo. Para manter a simplicidade e não usar caixas de diálogo (ainda não consideradas nessas notas) o evento on_confirm_dismiss=informe_dispensa apenas aciona a função informe_dispensa que registra na caixa de informações as ações de remoção dos controles pela direita ou pela esquerda, sem pedir a confirmação.
import flet as ft
def main(page):
def informe_dispensa(e: ft.DismissibleDismissEvent):
if e.direction == ft.DismissDirection.END_TO_START:
msg.value += "\nSaída pela direita!"
else:
msg.value += "\nSaída pela esquerda!"
e.control.confirm_dismiss(True)
page.update()
def dispensar(e):
coluna.controls.remove(e.control)
page.update()
def atualizar(e: ft.DismissibleUpdateEvent):
if e.direction == ft.DismissDirection.END_TO_START:
icone.name=ft.icons.ARROW_BACK
else:
icone.name=ft.icons.ARROW_FORWARD
texto.value=f"Progresso: {e.progress}"
page.update()
cor = [ft.colors.AMBER_100,ft.colors.BLUE_GREY_100, ft.colors.BLUE_50]
array=[
ft.Dismissible(
content=ft.Container(
ft.Text(f"Esta é a linha {i+1}", size=15),
height=35, width=380,
border = ft.border.all(2, ft.colors.BLACK54),
bgcolor= cor[i%2],
padding = ft.padding.all(6),
margin = ft.margin.all(2)
),
dismiss_direction=ft.DismissDirection.HORIZONTAL,
background=ft.Container(bgcolor=ft.colors.CYAN_100),
secondary_background=ft.Container(bgcolor=ft.colors.BROWN_50),
dismiss_thresholds={
ft.DismissDirection.END_TO_START: 0.2,
ft.DismissDirection.START_TO_END: 0.2
},
on_dismiss=dispensar,
on_update=atualizar,
on_confirm_dismiss=informe_dispensa
) for i in range(10)
]
coluna=ft.Column(array, spacing=1)
icone=ft.Icon(name=ft.icons.KEYBOARD, color=ft.colors.BLUE, size=30)
texto=ft.Text("Posição dos controles", size=18)
linha_info = ft.Row([icone, texto])
msg = ft.Text(f"Eventos capturados (Dispensar):\n" , size=15)
ver_acao = ft.Container(
msg,
height=100, width=380,
expand=True,
border = ft.border.all(2, ft.colors.BLACK54),
bgcolor= cor[2],
padding = ft.padding.all(12),
margin = ft.margin.all(3)
)
page.add(coluna, linha_info, ver_acao)
ft.app(main)

A operação array=[(objeto(i)) for i in range(10)] cria uma lista com 10 objetos objeto(i) passando o valor de i internamente para o objeto em cada loop.
A função informa_dispensa(e) recebe o evento e que contém uma descrição da direção do evento de arrastar. Ela atualiza a variável msg que é exibida dentro do container ver_acao.
A função dispensar(e) usa a referência ao controle e.control para removê-lo, usando coluna.controls.remove(e.control).
A função atualizar(e) escolhe um ícone de direção e insere texto mostrando a porcentagem de arrasto a cada momento, atualizando a variável texto que está em linha_lnfo.
