Containers en Fyne
En esta entrada veremos diferentes containers de fyne, y veremos que tal se ven al ser aplicados.
Esta entrada es un poco inusual para la clase de post que estoy realizando, pero decidí realizarla, ya que me he dado contra la pared más de un a vez utilizando esta herramienta para GO(GOLANG)
En fyne puede encontrar 2 clases de containers:
- AppTabs
- Box
NewHBox()
NewVBox()
Al menos eso dice el tutorial oficial de su página, sobre esto no estoy tan de acuerdo, ya que si miramos el package de container vemos varias formas de realizar un container (funciones).
Package Container
funciones en package container.
Estas son:
- New (return *fyne.container)
- NewAdaptiveGrid (return *fyne.container)
- NewBorder (return *fyne.container)
- NewCenter (return *fyne.container)
- NewGridWithColumns (return *fyne.container)
- NewGridWithRows (return *fyne.container)
- NewGridWrap (return *fyne.container)
- NewHBox (return *fyne.container)
- NewMax (return *fyne.container)
- NewPadded (return *fyne.container)
- NewVBox (return *fyne.container)
- NewWithoutLayout (return *fyne.container)
Si me pongo a ahondar en esto posiblemente me dé que muchos de estos pertenezcan al tipo de container box y es de suponer que es de esta manera.
Todas retornan *fyne.container
types en container package
Los tipos de container también es otra cosa que te deja pensando si en realidad hay 2 clases de contaieners. Estos son:
- AppTabs(container)
- TabItem(no es un container, especifica un item de AppTabs container )
- DocTabs(container)
- Scroll(container)
- ScrollDirection(no es un container, especifica la direccion del scroll en scroll container)
- Split(container)
- TabLocation(especifica donde esta el tab en AppTabs container)
Por lo que he estado observando todas las funciones pertenecen a containers de tipo box.
Por lo que he observado en la página principal hay documentación sin terminar o desactualizada, porque habla de 2 clases de container y ahondando encontré más de 2 quedando los containers de la siguiente manera:
- Box
- Apptabs
- DocTabs
- Scroll
- Split
Creando contenedores.
Si vas a probar el siguiente código te recomiendo instalar fyne en tu pc, es muy fácil de instalar solo sigue las instrucciones en fyne.io, en mi caso cree un nuevo proyecto que se llama fynecontainers.
No se deje intimidar por los … (esto es llamado ellipsis) solo indica que espera múltiples valores de ese tipo (0 o más)
En caso de que quieras ir probando agrega el siguiente código a tu main.go
main.go(imports y variables globales)package main import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" ) var btn_New *widget.Button var lbl1, lbl2, lbl3, lbl4, lbl5, lbl6, lbl7 *widget.Label
Además deberás agregar la siguiente función, esta creará nuestros labels que usaremos en los distintos containers
main.go(funcion labels)func labels() { lbl1 = widget.NewLabel("Label 1") lbl2 = widget.NewLabel("Label 2") lbl3 = widget.NewLabel("Label 3") lbl4 = widget.NewLabel("this is a long label") lbl5 = widget.NewLabel("this is an insane very long label") lbl6 = widget.NewLabel("----") lbl7 = widget.NewLabel("----") }
Para nuestra función main haremos lo siguiente:
main.go(funcion main)func main() { a := app.New() w := a.NewWindow("Fyne containers") labels() fcmessage := widget.NewLabel("All fine containers, plese clic a button to see an example") w.SetContent(container.NewVBox( fcmessage, // button code tocreate window with the container )) w.ShowAndRun() }
Lamentablemente la API Themes no tiene documentación alguna y por lo tanto no sé bien como ponerle color al container que utilizaremos.
Esto nos deja en cierta desventaja, ya que lo que pensaba hacer que la ventana se habrá al máximo o a un tamaño específico y luego utilizar un container, dentro de este poner el contendor especifico.
En pocas palabras quería que sucediera lo siguiente:
En este caso max tomaría toda el área de ventana, y el contenedor que estamos probando su área concreta de esta manera podríamos ver como seria, pero al no poder cambiarle el color al contenedor se me hace más difícil explicar cada container. Lo anterior expresado está mal vea NewMax para entender el porqué
Para satisfacer esta idea lo que hare es poner un label con texto ‘—-‘ dentro de el container MAX.
New
La función New espera un layout como parámetro y objetos del tipo fyne.CanvasObject como ya habíamos comentado fyne.Container también es un fyne.CanvasObject.
func New(layout fyne.Layout, objects ...fyne.CanvasObject) *fyne.Container
de valor nos retornará un *fyne.container después de todo es lo que esperamos.
Ejemplo:
Teniendo el código de la introducción creando contenedores en fyne, cree la siguiente función en main:
main.gofunc create_btn_New(app fyne.App) { btn_New = widget.NewButton("New", func() { window := app.NewWindow("(contaienr)New") window.SetContent( container.NewVBox( lbl6, container.New( layout.NewHBoxLayout(), lbl1, lbl2, lbl3, lbl4, lbl5, ), lbl7), ) window.Resize(fyne.NewSize(300, 300)) window.Show() }) }
Además de esta función deberíamos agregar el botón en las variables globales y llamar la función dentro de la función main.
main.go(función main)create_btn_New(a)main.go(despues de imports)
var btn_New *widget.Button
Probamos y el resultado debería ser el siguiente:
Como podemos ver el container creado con New toma el layout que le especifiquemos, en particular este container que creamos es idéntico a uno creado con NewHBox este toma todo el width del elemento que lo contiene y el height está dado por los elementos que lo conforman en este caso los labels (lbl1, lbl2, lbl3, lbl4, lbl5)
NewAdaptiveGrid
Esta función tiene como parámetro filas o columnas (rowcols) este parámetro nos dice cuantas tendrá dependiendo de la disposición que tenga eso lo veremos luego en el ejemplo. El resto de parámetros que puede tener son fyne.CanvasObjects.
func NewAdaptiveGrid(rowcols int, objects ...fyne.CanvasObject) *fyne.Container
Antes de seguir con el ejemplo recuerda que parte de lo que necesita este está en la introducción de creando contenedores.
Ahora si al ejemplo:
main.gofunc create_btn_NewAdaptiveGrid(app fyne.App) { btn_NewAdaptiveGrid = widget.NewButton("NewAdaptiveGrid", func() { window := app.NewWindow("(container)NewAdaptiveGrid") window.SetContent( container.NewVBox( lbl6, container.NewAdaptiveGrid(3, lbl1, lbl2, lbl3, lbl4, lbl5, ), lbl7), ) window.Resize(fyne.NewSize(300, 300)) window.Show() }) }
A nuestra función main deberemos agregarle la siguiente línea:
main.go(en función main)create_btn_NewAdaptiveGrid(a)
Además, luego de import agregaremos la variable del botón:
main.go(despues de imports)var btn_NewAdaptiveGrid *widget.Button
Como resultado obtendríamos el siguiente ejemplo
¿Ahora como cambiaríamos para que fueran rows?
Comming Soon
Under research, or under creation
NewBorder
Los container de tipo border son fijados a los objetos canvas que le digamos, estos son top, bottom, left, right estos son las aristas del container, recomiendo que rellenes 2 por lo menos o el resultado puede ser inesperado.
func NewBorder(top, bottom, left, right fyne.CanvasObject, objects ...fyne.CanvasObject) *fyne.Container
Para el ejemplo crea la siguiente funcion:
main.go(funcion para newBorder)func create_btn_NewBorder(app fyne.App) { btn_NewBorder = widget.NewButton("NewBorder", func() { window := app.NewWindow("(container)NewBorder") top := canvas.NewText("top bar", color.White) left := canvas.NewText("left", color.White) window.SetContent( container.NewVBox( container.NewBorder(top, nil, left, nil, container.NewVBox(lbl1, lbl2, lbl3, lbl4, lbl5), ), ), ) window.Resize(fyne.NewSize(500, 300)) window.Show() }) }
línea para que llame a la funcion en la funcion main:
main.go(en función main)create_btn_NewBorder(a)
tampoco olvides agregar el boton a el container
luego de esto agrega la variable que tendra el boton:
main.go(despues de imports)var btn_NewBorder *widget.Button
Por ultimo y lo que nos venia faltando es el resultado:
NewCenter
Crea un container que centra todos los objetos declarados dentro de el
func NewCenter(objects ...fyne.CanvasObject) *fyne.Container
He hecho el ejemplo pero lamentablemente no es lo que esperaba este amontono todos los label en el centro de el container quedando superpuestos. Si me preguntas como usarlo te dira que no utilices mas de 1 objeto dentro de el y asi por lo menos utilizarlo para alinear otro objeto.
NewGridWithColumns
esta funcion crea un container con una cantidad especfica de columnas especificada en el parametro cols, la cantidad de rows dependera de la cantidad de objetos que posea.
func NewGridWithColumns(cols int, objects ...fyne.CanvasObject) *fyne.Container
Ejemplo:
main.gofunc create_btn_NewGridWithColumns(app fyne.App) { btn_NewGridWithColumns = widget.NewButton("NewGridWithColumns", func() { window := app.NewWindow("(container)NewGridWithColumns") window.SetContent( container.NewVBox( container.NewHBox(lbl6), container.NewGridWithColumns(2, lbl1, lbl2, lbl3, lbl4, lbl5), container.NewHBox(lbl7), ), ) window.Resize(fyne.NewSize(500, 300)) window.Show() }) }
Para que el codigo anterior funcione debemos declarar el boton y tambien llamar la funcion en la funcion main
main.go(despues de imports)var btn_NewGridWithColumns *widget.Buttonmain.go(llama esta funcion antes definir el w.setContent)
create_btn_NewGridWithColumns(a)
el resultado seria el siguiente:
NewGridWithRows
Ejemplo:
main.go(agrega esta funcion)func create_btn_NewGridWithRows(app fyne.App) { btn_NewGridWithRows = widget.NewButton("NewGridWithRows", func() { window := app.NewWindow("(container)NewGridWithRows") window.SetContent( container.NewVBox( container.NewHBox(lbl6), container.NewGridWithRows(2, lbl1, lbl2, lbl3, lbl4, lbl5), container.NewHBox(lbl7), ), ) window.Resize(fyne.NewSize(500, 300)) window.Show() }) }
Agregamos la variable que contendra el boton
main.go(add this variable)var btn_NewGridWithRows *widget.Button
agregamos la llamada a la funcion
main.go(llama la funcion)create_btn_NewGridWithRows(a)
El resultado que nos daria
NewGridWrap
A diferencia de las funciones que venimos viendo para crear containers wrap nos permite decirle el tamaño que tendrán los objetos que estén dentro de este (realiza un resize).
func NewGridWrap(size fyne.Size, objects ...fyne.CanvasObject) *fyne.Container
Ejemplo:
func create_btn_NewGridWrap(app fyne.App) { btn_NewGridWrap = widget.NewButton("NewGridWrap", func() { window := app.NewWindow("(container)NewGridWrap") window.SetContent( container.NewVBox( container.NewHBox(lbl6), container.NewGridWrap(fyne.NewSize(100, 40), lbl1, lbl2, lbl3, lbl4, lbl5), container.NewHBox(lbl7), ), ) window.Resize(fyne.NewSize(500, 300)) window.Show() }) }
variable que contiene el botón
main.go(ponlo luego de import)var btn_NewGridWrap *widget.Button
llama la funcion detro de la funcion main
main.go(put it before setContent)create_btn_NewGridWrap(a)
tampoco te olvides de poner el botón en setcontent
Una vez termines el resultado debería ser como sigue:
como puedes observar deberás de tener cuidado de que el tamaño sea adecuado o puede haber superposicion. Algo a agregar es que este container en particular parece ser bastante responsive.
NewHBox
Cuando creamos un container con NewHBox este tomara todo el width(ancho) y la altura dependera de los objetos dentro de este(default).
func NewHBox(objects ...fyne.CanvasObject) *fyne.Container
Ejemplo:
main.go(add this function)func create_btn_NewHBox(app fyne.App) { btn_NewHBox = widget.NewButton("NewHBox", func() { window := app.NewWindow("(container)NewHBox") window.SetContent( container.NewVBox( lbl6, container.NewHBox(lbl1, lbl2, lbl3, lbl4, lbl5), lbl7, ), ) window.Resize(fyne.NewSize(500, 300)) window.Show() }) }
La variable que contendrá nuestro botón
main.go(add it after imports)var btn_NewHBox *widget.Button
llamo la función
main.go(add it before calling setContent)create_btn_NewHBox(a)
por último no olvides agregar tu botón en el set content
Cuando termines el resultado debería ser algo parecido al siguiente:
NewMax
NewMax no funciona tal como esperaba esta toma el espacio absoluto restante, lo cual puede ser algo util para poner imagenes debajo de la misma o cosas por el estilo. Si ponemos contenedores dentro compartiendo espacio con widgets puede darnos resultados indeseados.
func NewMax(objects ...fyne.CanvasObject) *fyne.Container
Ejemplo:
main.go(add this function)func create_btn_NewMax(app fyne.App) { btn_NewMax = widget.NewButton("NewMax", func() { window := app.NewWindow("(container)NewMax") window.SetContent( container.NewVBox( container.NewMax(container.NewHBox(lbl1, lbl2, lbl3, lbl4, lbl5), container.NewHBox(widget.NewLabel("hi there"))), lbl6, lbl7, ), ) window.Resize(fyne.NewSize(500, 300)) window.Show() }) }
Agregamos el boton:
main.go (add after imports)var btn_NewMax *widget.Button
Llamamos la funcion en main:
main.go (call it on main)create_btn_NewMax(a)
y agregamos el boton al setContent
El resultado de esto deberia ser algo parecido al siguiente:
Work-in-progress
The text that continues is being created and could change
NewPadded
Crea un container con los objetos que se encuentren detro de el con un padding que viene por defecto.
func NewPadded(objects ...fyne.CanvasObject) *fyne.Container
NewVBox
En caso de usar NewVBox para crear un container este tomara toda la altura(height) del objeto que lo contiene y su ancho dependera de los objetos que contenga.
func NewVBox(objects ...fyne.CanvasObject) *fyne.Container
NewWithoutLayout
func NewWithoutLayout(objects ...fyne.CanvasObject) *fyne.Container
Los container de fyne pueden ser combinados
bueno esta seccion es media obvia ya que en los ejemplos anteriores ya estabamos combinando un container MAX con otro
En esta seccion combinaremos un container HBox con 2 VBox
Work-in-progress-end
Work in progress ended keep reading without worrying