Entre los correos y mensajes en facebook y whatsapp que me llegan (y de entrada pido perdón a quienes no puedo responder o me olvide responder) me preguntaron como hacer un efecto flip (dar la vuelta) para un botón en java.
Bueno java cuenta con clases y métodos que nos permiten manipular imágenes, no son los mejores pero es lo que hay y con un poco de imaginación podemos hacer casi cualquier cosa. En el siguiente tutorial crearemos un componente swing que nos permita implementar el efecto flip con imágenes
Necesitamos
Tiempo 30 minutos
Nivel: Intermedio
TUTORIAL EFECTO FLIP
Paso 1. El Proyecto
File -> New project… -> Java Class Library, en nombre de proyecto ponemos JFlip y presionamos el boton finish para terminar la creación del proyecto.
A continuación creamos la estructura del proyecto como se ve a continuación:
Paso 2. Flip
Abre la clase JFlip:
package com.bolivia.flip; public class JFlip { }
La clase JFlip se extenderá de la clase JComponent, esta clase es la base de todas los componentes swing exceptuando algunos casos. Al extender de la clase JComponent tenemos la base perfecta para desarrollar nuestro swing.
Así también necesitamos controlar eventos del mouse por lo que implementaremos un MouseListener, nuestra clase queda de la siguiente forma:
import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JComponent; public class JFlip extends JComponent implements MouseListener{ /**Constructor de clase*/ public JFlip(){} @Override public void mouseClicked(MouseEvent e) {/*...*/} @Override public void mousePressed(MouseEvent e) {/*...*/} @Override public void mouseReleased(MouseEvent e) {/*...*/} @Override public void mouseEntered(MouseEvent e) {/*...*/} @Override public void mouseExited(MouseEvent e) {/*...*/} }
Antes de continuar con la codificación, debemos analizar como emular en dos dimensiones el «efecto flip» siendo que en la realidad ese efecto se produce en tres dimensiones. El problema se reduce a un efecto de perspectiva es decir cuando el plano da vuelta a nuestros ojos un lado se hace más pequeño a medida que gira hasta desaparecer y reaparecer del otro lado pero esta vez aumentando de tamaño hasta alcanzar su tamaño original, en las imágenes siguientes podemos ver gráficamente a que me refiero:
Nuestro plano que es un polígono tiene 4 esquinas (A,B,C y D) , los puntos Ax, Cx, Bx y Dx tienen un desplazamiento horizontal uniforme hacia la mitad del plano, los puntos Ay y Cy son constantes, en cambio los puntos By y Dy tienen un movimiento vertical uniforme menor al desplazamiento horizontal, es menor porque no queremos que los puntos By y Dy se intercepten lo que arruinaría el efecto flip. Cuando los puntos Ax, Cx, Bx y Dx llegan hasta la mitad del plano, se debe invertir el procedimiento, es decir, los puntos Ax, Cx, Bx y Dx tienen ahora un desplazamiento negativo y el desplazamiento vertical también lo es, pero, las variables By y Dy se vuelven constantes y Ay y Cy son los que se desplazan en sentido vertical . Es decir:
Otro punto importante a considerar es que java nos permite recortar pedazos de una imagen pero esos pedazos deben ser rectangulares, por lo que no podremos hacer uso de esos métodos en este proyecto, sin embargo si podemos usar un objeto Shape para pintar secciones irregulares de una imagen usando las coordenadas del polígono descrito más arriba y así simular el efecto en perspectiva, no es lo ideal pero gracias al movimiento constante nuestros ojos no notaran la diferencia.
Continuemos con la programación
Los imports que usamos en la clase flip son:
import java.awt.BasicStroke; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.GeneralPath; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.Timer;
Declaramos las variables:
private Timer timer = null; private boolean inTransition = false; private int speed = 12;//velocidad de flip en milisegundos private int displacement = 2;//desplazamiento en pixeles private boolean isFront = true; private boolean inward = true;//sentido del desplazamiento //iconos por defecto private Icon iconBack = new ImageIcon(getClass().getResource("/com/bolivia/resource/photo1.jpg")); private Icon iconFront = new ImageIcon(getClass().getResource("/com/bolivia/resource/photo2.jpg")); private Image image = ((ImageIcon)iconFront).getImage(); //variables de desplazamiento private int displacementHorizontal = 0; private float displacementLeft = 0; private float displacementRight = 0; //tamaño por defecto private Dimension dimension = new Dimension(160,160);
OJO: Utilizaremos dos imágenes de 160×160 pixeles que colocaremos en el paquete /resource/
A continuación declaramos el constructor de clase, sobreescribimos el método paintComponent() y definimos el método flipAnimate() para los cambios de variable de desplazamiento
/**Constructor de clase*/ public JFlip(){ super(); setSize(dimension); setPreferredSize(dimension); setVisible(true); addMouseListener(JFlip.this); } @Override public void paintComponent(Graphics g){ Graphics2D g2 =(Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke( 0f )); //coordenas de imagen GeneralPath p = new GeneralPath(); p.moveTo(displacementHorizontal, displacementLeft);//esquina A p.lineTo(getWidth()-displacementHorizontal-1, displacementRight);//esquina B p.lineTo(getWidth()-displacementHorizontal-1, getHeight()-displacementRight-1);//esquina D p.lineTo( displacementHorizontal, getHeight()-displacementLeft-1 );//esquina C p.closePath(); Shape shp = p; g2.setClip(shp); g2.drawImage(image, 0, 0,getWidth() - displacementHorizontal,getHeight(), null); g2.setClip(null); g2.draw(shp); g.dispose(); } /** * Metodo que realiza los cambios en las variables de desplazamiento * @return Void */ private void flipAnimate(){ inTransition = !inTransition; //declaramos un evento para modificar el desplazamiento vertical y horizontal ActionListener animation = new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { if(inward){ displacementHorizontal += displacement; displacementRight += (displacementRight>=getHeight()/2)?0:displacement/(getSize().getWidth()/getSize().getHeight()+1f); }else{ displacementHorizontal -= displacement; displacementLeft -=displacement/(getSize().getWidth()/getSize().getHeight()+1f); } //repinta graficos repaint(); //si se llego al medio del componente -> cambia de sentido if(displacementHorizontal >= getWidth()/2){ inward = false; displacementLeft = displacementRight; displacementRight=0; // if( isFront ){//mostrar imagen de atras isFront=false; image=((ImageIcon)iconBack).getImage(); }else{//mostrar imagen de adelante isFront =true; image=((ImageIcon)iconFront).getImage(); } } //volvio a su posicion inicial -> detener animacion if( inward == false && displacementHorizontal == 0 ){ inTransition=false; timer.stop(); displacementLeft=0; displacementRight=0; displacementHorizontal=0; inward = true; } } }; // if( inTransition ) { if(timer != null)timer.stop(); timer = new Timer( speed, animation); timer.start(); //inicia animacion } }
El efecto flip se llevara a cabo cuando el usuario de un clic sobre el swing, por lo que debemos invocar al metodo flipAnimate() en el evento mouseClicked, nuestra clase final queda de la siguiente forma:
package com.bolivia.flip; import java.awt.BasicStroke; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.GeneralPath; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.Timer; /** * @web https://www.jc-mouse.net/ * @author Mouse */ public class JFlip extends JComponent implements MouseListener { private Timer timer = null; private boolean inTransition = false; private int speed = 4;//velocidad de flip en milisegundos private int displacement = 2;//desplazamiento en pixeles private boolean isFront = true; private boolean inward = true;//sentido del desplazamiento //iconos por defecto private Icon iconBack = new ImageIcon(getClass().getResource("/com/bolivia/resource/photo1.jpg")); private Icon iconFront = new ImageIcon(getClass().getResource("/com/bolivia/resource/photo2.jpg")); private Image image = ((ImageIcon)iconFront).getImage(); //variables de desplazamiento private int displacementHorizontal = 0; private float displacementLeft = 0; private float displacementRight = 0; //tamaño por defecto private Dimension dimension = new Dimension(160,160); /**Constructor de clase*/ public JFlip(){ super(); setSize(dimension); setPreferredSize(dimension); setVisible(true); addMouseListener(JFlip.this); } @Override public void paintComponent(Graphics g){ Graphics2D g2 =(Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke( 0f )); //coordenas de imagen GeneralPath p = new GeneralPath(); p.moveTo(displacementHorizontal, displacementLeft);//esquina A p.lineTo(getWidth()-displacementHorizontal-1, displacementRight);//esquina B p.lineTo(getWidth()-displacementHorizontal-1, getHeight()-displacementRight-1);//esquina D p.lineTo( displacementHorizontal, getHeight()-displacementLeft-1 );//esquina C p.closePath(); Shape shp = p; g2.setClip(shp); g2.drawImage(image, 0, 0,getWidth() - displacementHorizontal,getHeight(), null); g2.setClip(null); g2.draw(shp); g.dispose(); } /** * Metodo que realiza los cambios en las variables de desplazamiento * @return Void */ private void flipAnimate(){ inTransition = !inTransition; //declaramos un evento para modificar el desplazamiento vertical y horizontal ActionListener animation = new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { if(inward){ displacementHorizontal += displacement; displacementRight += (displacementRight>=getHeight()/2)?0:displacement/(getSize().getWidth()/getSize().getHeight()+1f); }else{ displacementHorizontal -= displacement; displacementLeft -=displacement/(getSize().getWidth()/getSize().getHeight()+1f); } //repinta graficos repaint(); //si se llego al medio del componente -> cambia de sentido if(displacementHorizontal >= getWidth()/2){ inward = false; displacementLeft = displacementRight; displacementRight=0; // if( isFront ){//mostrar imagen de atras isFront=false; image=((ImageIcon)iconBack).getImage(); }else{//mostrar imagen de adelante isFront =true; image=((ImageIcon)iconFront).getImage(); } } //volvio a su posicion inicial -> detener animacion if( inward == false && displacementHorizontal == 0 ){ inTransition=false; timer.stop(); displacementLeft=0; displacementRight=0; displacementHorizontal=0; inward = true; } } }; // if( inTransition ) { if(timer != null)timer.stop(); timer = new Timer( speed, animation); timer.start(); //inicia animacion } } @Override public void mouseClicked(MouseEvent e) { flipAnimate(); } @Override public void mousePressed(MouseEvent e) {/*...*/} @Override public void mouseReleased(MouseEvent e) {/*...*/} @Override public void mouseEntered(MouseEvent e) {/*...*/} @Override public void mouseExited(MouseEvent e) {/*...*/} public Icon getIconBack() { return iconBack; } public void setIconBack(Icon iconBack) { this.iconBack = iconBack; } public Icon getIconFront() { return iconFront; } public void setIconFront(Icon iconFront) { this.iconFront = iconFront; } public int getDisplacement() { return displacement; } public void setDisplacement(int displacement) { this.displacement = displacement; } public int getSpeed() { return speed; } public void setSpeed(int speed) { this.speed = speed; } }//JFlip:end
Compilamos el proyecto, para usar el componente solo lo arrastramos al jframe y también podemos modificar la velocidad de animación, la cantidad de desplazamiento en pixeles y cargar nuevas imagenes desde su menú de propiedades, ejecutamos y probamos el efecto flip.
Descargar proyecto FLIP aquí 🙂
enjoy!!!
Yo soy yo :) JC Mouse, Soy orgullosamente boliviano soy fundador y CEO de la web jc-Mouse.net uno de las pocas web en emprendimiento y tecnología en Bolivia.
Toda la información que encuentres en este sitio es y sera completamente gratis siempre, puedes copiar, descargar y re-publicar si así lo deseas en otros blogs o sitios web, solo te pido a cambio que dejes una referencia a esta web. Esto nos ayuda a crecer y seguir aportando. Bye
Enjoy! :)
Los objetos como JLabel o JButton nos permiten hacer uso de código CSS en su propiedad TEXT, asi podemos adornar el text...
Cuando se desarrolla una aplicación, puede ser un requisito que este tenga soporte para varias tipos de base de datos, s...
Un Action Provider es un elemento que habita en la Action Bar para incrementar la accesibilidad de nuestras aplicaciones...
Muchas veces necesitamos de fotos para adornar nuestros perfiles en RRSS pero no queremos subir nuestras propias fotos p...
¿Alguna vez tuviste la necesidad de hacer una captura de pantalla de una página web? Si es así, seguramente buscaste y d...
iReport nos da la posibilidad de dar un formato condicional a los diferentes registros resultado de nuestras consultas S...
El gigante tecnologico Google a puesto un bonito Doodle en su buscador que esta fascinando a sus millones de usuarios qu...
WhatsApp anuncio a través de su blog que ya se encuentra disponible la función de envío de fotos y videos TEMPORALES, es...
Muchas de las innovaciones computacionales de la NASA se desarrollaron para ayudar a explorar el espacio, pero ahora la...
TikTok es una plataforma de microvideos muy popular entre los jóvenes el cual cuenta ya con millones de videos cortps de...