Integrating an App Layout
En este paso, reunirás todas las partes de tu aplicación en un diseño cohesivo. Al final de este paso, la estructura de tu aplicación se parecerá mucho al arquetipo de SideMenu, y tendrás una mejor comprensión de cómo funcionan los siguientes componentes y conceptos:
Ejecutando la aplicación
A medida que desarrollas tu aplicación, puedes usar 6-integrating-an-app-layout como comparación. Para ver la aplicación en acción:
-
Navega al directorio de nivel superior que contiene el archivo
pom.xml, que es6-integrating-an-app-layoutsi estás siguiendo la versión en GitHub. -
Usa el siguiente comando de Maven para ejecutar la aplicación de Spring Boot localmente:
mvn
Ejecutar la aplicación abre automáticamente un nuevo navegador en http://localhost:8080.
Creando un componente reutilizable
En un paso anterior, Routing and Composites, creaste dos componentes compuestos que contenían el contenido de la tabla de clientes y el formulario de clientes. Como parte de este paso, crearás un componente compuesto más pequeño y reutilizable para mostrar el nombre de la aplicación dentro del menú lateral y una página de información. Si decides cambiar el nombre de la aplicación en el futuro, solo tendrías que actualizarlo en este componente.
En src/main/java/com/webforj/tutorial/components, crea una clase llamada AppTitle. El componente vinculado para AppTitle será un FlexLayout, un componente contenedor que se utiliza a lo largo de este paso para mostrarte cómo hacer diseños más complejos. Para este FlexLayout, organizarás la dirección de los elementos y el espaciado entre ellos. Eso se logra utilizando los métodos setDirection() y setSpacing() respectivamente.
// Haz que el componente vinculado sea un FlexLayout
public class AppTitle extends Composite<FlexLayout> {
private FlexLayout self = getBoundComponent();
public AppTitle() {
// Organiza los elementos verticalmente
self.setDirection(FlexDirection.COLUMN);
// Establece el espacio entre elementos
self.setSpacing("0px");
}
}
Luego utiliza elementos HTML estándar para crear el título y el subtítulo. Establecer el margen inferior de un elemento de encabezado en 0px acerca los elementos, y puedes dar estilo al subtítulo utilizando variables CSS de DWC.
public class AppTitle extends Composite<FlexLayout> {
private FlexLayout self = getBoundComponent();
private H2 title = new H2("Gestor de Clientes");
private Paragraph subTitle = new Paragraph("Un Sistema de Registros Sencillo");
public AppTitle() {
title.setStyle("margin-bottom", "0px");
subTitle.setStyle("color", "var(--dwc-color-gray-50)");
subTitle.setStyle("font-size", "var(--dwc-font-size-m)");
self.setDirection(FlexDirection.COLUMN)
.setSpacing("0px")
.add(title, subTitle);
}
}
Renderizado opcional
Aunque AppTitle es simple, agregar un argumento booleano al método del constructor te permite controlar cuándo renderizar ciertas partes del componente, como el subtítulo.
// Agregar un argumento booleano
public AppTitle(boolean showSubTitle) {
self.setDirection(FlexDirection.COLUMN)
.setSpacing("0px")
// Agregar el título por defecto
.add(title);
// Opcionalmente muestra el subtítulo
if (showSubTitle) {
self.add(subTitle);
}
}
AppTitle completado
Juntos, el componente reutilizable debería verse como sigue:
public class AppTitle extends Composite<FlexLayout> {
private FlexLayout self = getBoundComponent();
private H2 title = new H2("Gestor de Clientes");
private Paragraph subTitle = new Paragraph("Un Sistema de Registros Sencillo");
public AppTitle(boolean showSubTitle) {
title.setStyle("margin-bottom", "0");
subTitle.setStyle("color", "var(--dwc-color-gray-50)");
subTitle.setStyle("font-size", "var(--dwc-font-size-m)");
self.setDirection(FlexDirection.COLUMN)
.setSpacing("0px")
.add(title);
if (showSubTitle) {
self.add(subTitle);
}
}
}
Creando una página de información
El primer lugar para agregar el componente AppTitle recién creado será una página de información. Esta página incluye una imagen y el componente AppTitle, centrado en la página usando otro FlexLayout.
Centrar contenido usando un FlexLayout
El objetivo es centrar el contenido de la página de información usando el FlexLayout. El componente FlexLayout sigue el modelo de diseño de flexbox de CSS. Los métodos para el FlexLayout, como los utilizados anteriormente para orientar los elementos en una columna, son diferentes maneras de organizar los elementos.
Los métodos para organizar elementos en un FlexLayout utilizan un sistema direccional relativo. En lugar de pensar en los ejes horizontal y vertical, es mejor pensar en el eje paralelo a los elementos como el eje principal, y el eje perpendicular a los elementos como el eje cruzado.
Establecer tanto las propiedades FlexJustifyContent como FlexAlignment en CENTER centrará los elementos a lo largo de ambos ejes, principal y cruzado, en el FlexLayout, y hacer que el FlexLayout ocupe la totalidad de su contenedor padre lo hace centrado en la página.
private final FlexLayout layout = new FlexLayout();
// Llenar todo el espacio del elemento padre
layout.setSize("100%", "100%");
// Hacer que el eje principal sea vertical
layout.setDirection(FlexDirection.COLUMN);
// Centrar los elementos a lo largo del eje cruzado
layout.setAlignment(FlexAlignment.CENTER);
// Centrar los elementos a lo largo del eje principal
layout.setJustifyContent(FlexJustifyContent.CENTER);
Para ayudarte a visualizar cómo funcionan los diferentes métodos, echa un vistazo al blog FlexWrap your mind around webforJ's FlexLayout.
Agregando recursos
Uno de los elementos que irá dentro del FlexLayout centrado es una imagen. Para este tutorial, puedes ver y descargar la imagen de la página de información en GitHub. Una vez descargada, agrégala a la carpeta estática de tu proyecto en src/main/resources/static/images y nómbrala Files.svg.
Colocar esta imagen en la carpeta estática te permite referenciarla utilizando el protocolo del Servidor Web, como hiciste al referenciar el archivo CSS en el primer paso, Creando una Aplicación Básica. Luego, puedes usarla dentro de tu aplicación como un elemento HTML, así:
private Img fileImg = new Img("ws://images/Files.svg");
Creando AboutView
Al igual que las dos páginas de la aplicación existentes, la página de información será una vista enrutada. En src/main/java/com/webforj/tutorial/views, agrega una clase llamada AboutView. Usa un FlexLayout como el componente vinculado, como lo hiciste para AppTitle.
Dado que has nombrado la clase AboutView, no hay necesidad de dar un valor personalizado para el mapeo de URL; esta página se renderiza en http://localhost:8080/about por defecto.
Aquí tienes cómo se ve al usar los conceptos de los pasos anteriores con los componentes recién creados para crear una nueva vista con contenido centrado:
@Route()
@FrameTitle("Acerca de")
public class AboutView extends Composite<FlexLayout> {
private FlexLayout self = getBoundComponent();
private Img fileImg = new Img("ws://images/Files.svg");
public AboutView() {
fileImg.setWidth(250);
self.setSize("100%", "100%")
.setDirection(FlexDirection.COLUMN)
.setAlignment(FlexAlignment.CENTER)
.setJustifyContent(FlexJustifyContent.CENTER)
.add(fileImg, new AppTitle(false));
}
}
Creando la ruta Layout
Se menciona brevemente en el paso de Routing and Composites, pero hay dos tipos de rutas. MainView, FormView y AboutView son todas rutas de View, mientras que el tipo de ruta que usarás para crear el menú lateral de la aplicación es una ruta de Layout.
Las rutas de Layout envuelven las vistas secundarias y permiten que ciertas partes de la UI persistan a través de vistas, como un menú lateral. En src/main/java/com/webforj/tutorial/layouts, crea una clase llamada MainLayout.
Route outlets
Al igual que las rutas de vista, MainLayout necesita una anotación @Route. Sin embargo, dado que tiene Layout como sufijo y las rutas de layout no contribuyen a la URL, esta anotación no necesita argumentos.
@Route
public class MainLayout {
public MainLayout() {
}
}
La aplicación sabe qué vistas renderizar dentro de MainLayout declarando la clase de layout como la salida de ruta en cada vista. Los pasos anteriores solo tienen un atributo value establecido en las anotaciones @Route, así que ahora necesitarás declarar explícitamente cuáles son los atributos value y outlet para las clases de vista.
- MainView
- FormView
- AboutView
@Route(value = "/", outlet = MainLayout.class)
@Route(value = "customer/:id?<[0-9]+>", outlet = MainLayout.class)
@Route(outlet = MainLayout.class)
Esta es la última modificación requerida para FormView y AboutView en este paso, así que recuerda actualizar la anotación @Route para esas vistas antes de ejecutar tu aplicación.
Usando el componente AppLayout
Ahora que tu aplicación renderiza las vistas dentro de MainLayout, puedes elegir dónde se renderizan esos componentes. Elegir el AppLayout como el componente vinculado para MainLayout te permite almacenar las vistas en un área de contenido principal por defecto, mientras también te da diferentes áreas para agregar elementos para el encabezado y el menú lateral.
Slots
Para muchos contenedores webforJ, utilizar los métodos add() agrega componentes de UI al área de contenido principal. En el componente AppLayout, hay múltiples áreas para agregar componentes de UI, cada una en una ranura separada. Al marcar MainLayout como una ruta de layout y establecer su componente vinculado como un AppLayout, las vistas se renderizan automáticamente en la ranura de contenido principal.
En este paso, usarás las ranuras drawer-title y drawer para crear un menú lateral, y la ranura header para mostrar qué página está el usuario y un interruptor para el menú lateral.
Creando un menú lateral
Cuando hay suficiente espacio en la pantalla del dispositivo, el componente AppLayout muestra un cajón. Aquí agregarás nuevamente el AppTitle y elementos que permitirán a los usuarios navegar por la aplicación.
Por defecto, AppLayout no muestra un encabezado de cajón, pero usar el método setDrawerHeaderVisible() te permite mostrar elementos que están dentro de la ranura drawer-title, que será el AppTitle con su subtítulo mostrado.
private AppLayout appLayout = new AppLayout();
// Mostrar el Encabezado del Cajón
appLayout.setDrawerHeaderVisible(true);
// Agregar el AppTitle al Encabezado del Cajón con su subtítulo
appLayout.addToDrawerTitle(new AppTitle(true));
La ranura drawer debería contener los componentes que permiten a los usuarios navegar en la aplicación. Usar el componente AppNav hace fácil crear nuevas opciones de navegación. Para cada enlace, solo necesitas crear un AppNavItem. Los componentes AppNavItem en este tutorial utilizan tres parámetros:
Agrupar todas las configuraciones del cajón en MainLayout se ve como sigue:
@Route
public class MainLayout extends Composite<AppLayout> {
private AppLayout self = getBoundComponent();
private AppNav appNav = new AppNav();
public MainLayout() {
setDrawer();
}
private void setDrawer() {
self.setDrawerHeaderVisible(true)
.addToDrawerTitle(new AppTitle(true));
appNav.addItem(new AppNavItem("Tablero", MainView.class,
TablerIcon.create("archive")));
appNav.addItem(new AppNavItem("Acerca de", AboutView.class,
TablerIcon.create("info-circle")));
self.addToDrawer(appNav);
}
}
Creando un encabezado
La ranura header debería incluir dos elementos: un interruptor para mostrar u ocultar el menú lateral y una forma de mostrar el título del marco. Ambos elementos estarán dentro de un componente Toolbar, otra forma de organizar componentes.
Puedes incluir el interruptor para el cajón AppLayout con el componente AppDrawerToggle. Este componente ya está estilizado con un ícono comúnmente utilizado para opciones de menú ocultas y apunta al cajón para abrirlo y cerrarlo.
// Crear los componentes contenedores
private AppLayout appLayout = new AppLayout();
private Toolbar toolbar = new Toolbar();
// Agregar la Toolbar al encabezado de AppLayout
appLayout.addToHeader(toolbar);
// Agregar el AppDrawerToggle a la barra de herramientas
toolbar.addToStart(new AppDrawerToggle());
El encabezado también puede mostrar el título del marco utilizando el evento de navegación para recuperar detalles sobre el componente entrante, mientras tiene un listener de eventos para eliminar el registro y prevenir fugas de memoria.
// Crear el elemento H1 y el registro de navegación
private H1 title = new H1("");
private ListenerRegistration<NavigateEvent> navigateRegistration;
// Registrar el evento al navegar
navigateRegistration = Router.getCurrent().onNavigate(this::onNavigate);
// Eliminar escuchadores antes de destruir MainLayout
@Override
protected void onDidDestroy() {
if (navigateRegistration != null) {
navigateRegistration.remove();
}
}
// Recuperar el título del marco de la clase de vista entrante
private void onNavigate(NavigateEvent ev) {
Component component = ev.getContext().getComponent();
if (component != null) {
FrameTitle frameTitle = component.getClass().getAnnotation(FrameTitle.class);
title.setText(frameTitle != null ? frameTitle.value() : "");
}
}
MainLayout completado
Aquí está MainLayout con el contenido creado para el cajón y el encabezado dentro de un AppLayout:
Actualizando FormView
Como se mencionó previamente, el único cambio en FormView fue en la anotación @Route.
@Route(value = "customer/:id?<[0-9]+>", outlet = MainLayout.class)
Actualizando MainView
Para MainView, cambiarás el componente vinculado de un Div a un FlexLayout. Esto te permite centrar la tabla, mientras mueves componentes específicos dentro del diseño. Usar el método setItemAlignment() te permite elegir un componente en el diseño y moverlo, así puedes mantener la tabla centrada mientras anclas el botón de agregar cliente en la esquina superior derecha del diseño.
// Cambiar el componente vinculado a un FlexLayout
private FlexLayout self = getBoundComponent();
// Alinear el botón al final del eje cruzado
self.setItemAlignment(FlexAlignment.END, addCustomer);
Otra mejora que puedes hacer aquí es el ancho de la tabla. En lugar de un ancho fijo, puedes establecerlo para que coincida con su contenedor padre, el FlexLayout. Luego ese FlexLayout puede tener un ancho máximo para que no se estire demasiado en pantallas más grandes.
private FlexLayout self = getBoundComponent();
private Table<Customer> table = new Table<>();
self.setSize("100%", "100%");
self.setMaxWidth(2000);
table.setSize("100%", "294px");
Uniendo estos elementos y haciendo otro método para obtener el FlexLayout centrado como los anteriores, hace que MainView con los cambios resaltados se vea así: