Sigueme en Facebook Sigueme en Twitter Sigueme en Instagram Sigueme en Youtube
JC Mouse Bolivia
Index / Java / Crea un efecto Flip en java swing

Crea un efecto Flip en java swing

Autor jc mouse lunes, octubre 5, 2015

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

  • IDE Netbeans

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:

jflip

  • JFlip.java es una clase y es nuestro componente en si, es donde colocaremos el código necesario para el efecto flip
  • DemoFrame.java es un JFrame y nos servirá para probar nuestro swing
  • resource/ es un paquete, ahí colocaremos las imágenes que usemos en el proyecto

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:

flip perspective

dar la vuelta

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:

java swing flip

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.

dog

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!!!

Tags

Si te ha gustado podrías compartirlo o dejar un comentario. ¡Muchas gracias!
Autor: JC Mouse

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! :)

También Te Podría Interesar

Código CSS en Java/Netbeans

Código CSS en Java/Netbeans

Los objetos como JLabel o JButton nos permiten hacer uso de código CSS en su propiedad TEXT, asi podemos adornar el text...

Utiliza 2 bases de datos diferentes en una aplicación parte I

Utiliza 2 bases de datos diferentes en una aplicación parte I

Cuando se desarrolla una aplicación, puede ser un requisito que este tenga soporte para varias tipos de base de datos, s...

Compartir texto plano con un ShareActionProvider en Android

Compartir texto plano con un ShareActionProvider en Android

Un Action Provider es un elemento que habita en la Action Bar para incrementar la accesibilidad de nuestras aplicaciones...

Genera fotos para tu perfil de RRSS con I.A. y protege tu identidad

Genera fotos para tu perfil de RRSS con I.A. y protege tu identidad

Muchas veces necesitamos de fotos para adornar nuestros perfiles en RRSS pero no queremos subir nuestras propias fotos p...

Captura de pantalla de una web con Chrome

Captura de pantalla de una web con Chrome

¿Alguna vez tuviste la necesidad de hacer una captura de pantalla de una página web? Si es así, seguramente buscaste y d...

Estilos condicionales en iReport

Estilos condicionales en iReport

iReport nos da la posibilidad de dar un formato condicional a los diferentes registros resultado de nuestras consultas S...

Comparte lo que sabes

Categorias

Últimas entradas

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...

Herramientas

Generador de Enlaces a Whatsapp