Java - Modern Toggle Buttons in Java Swing

How to Create Animated Toggle Buttons in Java Netbeans

How to Create Animated Toggle Buttons in Java Netbeans


In this Java Tutorial we will see How To Create Toggle Buttons with five different styles: Neon, Gradient, Minimal, Cyberpunk, and Neumorphic In Java Using Netbeans.

What We Are Gonna Use In This Project:

- Java Programming Language.
- NetBeans Editor.





Project Source Code:



/**
 *
 * @author 1BestCsharp
 */
public class ModernToggleButtons extends JFrame {

    public ModernToggleButtons(){
        
        // Set the title of the window
        setTitle("Modern Toggle Buttons");
        // Make the application close when the window is closed
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // Set the initial size of the window
        setSize(500, 600);
        // Center the window on the screen
        setLocationRelativeTo(null);
        
        // Create the main panel that will hold all components
        JPanel mainPanel = new JPanel();
        // Set the layout to stack components vertically
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        // Set the background color to dark gray (RGB: 26, 26, 26)
        mainPanel.setBackground(new Color(26, 26, 26));
        // Add a 20-pixel empty border around all sides of the panel
        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        
        // Add toggle buttons with labels and vertical spacing
        mainPanel.add(createTogglePanel("Neon", new NeonToggleButton()));
        mainPanel.add(Box.createVerticalStrut(30));
        mainPanel.add(createTogglePanel("Gradient", new GradientToggleButton()));
        mainPanel.add(Box.createVerticalStrut(30));
        mainPanel.add(createTogglePanel("Minimal", new MinimalToggleButton()));
        mainPanel.add(Box.createVerticalStrut(30));
        mainPanel.add(createTogglePanel("Cyberpunk", new CyberpunkToggleButton()));
        mainPanel.add(Box.createVerticalStrut(30));
        mainPanel.add(createTogglePanel("Neumorphic", new NeumorphicToggleButton()));
        
        
        // Add the main panel to the JFrame window
        add(mainPanel);
        
    }
    
    
    
    // Method that creates a panel containing a label, toggle button, and status label
    private JPanel createTogglePanel(String label, JToggleButton toggleButton){
        
        // Create a new panel to hold the components
        JPanel panel = new JPanel();
        // Use FlowLayout to arrange components horizontally with 20-pixel horizontal gaps
        panel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 0));
        // Set the panel's background color to dark gray
        panel.setBackground(new Color(26, 26, 26));
        
        // Create a label with the specified text
        JLabel nameLabel = new JLabel(label);
        // Set the label's text color to white
        nameLabel.setForeground(Color.WHITE);
        // Set the font to Segoe UI, normal style, 24-point size
        nameLabel.setFont(new Font("Segoe UI", Font.PLAIN, 24));
        // Set a fixed size for the label
        nameLabel.setPreferredSize(new Dimension(150, 30));
        
         // Create a label that will show "ON" or "OFF" status
        JLabel statusLabel = new JLabel("OFF");
        // Set the status label's text color to white
        statusLabel.setForeground(Color.WHITE);
        // Set the font to Segoe UI, normal style, 20-point size
        statusLabel.setFont(new Font("Segoe UI", Font.PLAIN, 20));
        // Set a fixed size for the status label
        statusLabel.setPreferredSize(new Dimension(70, 30));
        
        // Check if the toggle button is an instance of our custom BaseToggleButton class
         if (toggleButton instanceof BaseToggleButton) {
             
            // Cast the toggle button to BaseToggleButton to access its specific methods
            BaseToggleButton baseToggle = (BaseToggleButton) toggleButton;
            // Set a callback function that updates the status label when the toggle state changes
            baseToggle.setStatusUpdateCallback(isOn -> {
                
                // Update the text to show "ON" or "OFF"
                statusLabel.setText(isOn ? "ON" : "OFF");
                // Change the text color to green when ON, white when OFF
                statusLabel.setForeground(isOn ? new Color(0, 255, 136) : Color.WHITE);
                
            });
             
         }

        // Add the components to the panel
        panel.add(nameLabel);
        panel.add(toggleButton);
        panel.add(statusLabel);
        
        return panel;
        
    }
    
    
    
    
    // Abstract base class for all custom toggle buttons
    private abstract class BaseToggleButton extends JToggleButton {
        
        // Value between 0.0 (OFF) and 1.0 (ON) for animation progress
        protected float animationProgress = 0.0f;
        // Timer object to handle the animation
        protected Timer animationTimer;
        // Duration of the animation in milliseconds
        protected final int ANIMATION_DURATION = 200;
        // Number of steps in the animation
        protected final int ANIMATION_STEPS = 20;
       // Callback function that will be called when the toggle state changes
        protected Runnable statusUpdateCallback;
        
        public BaseToggleButton(){
            
            // Set the size of the button
            setPreferredSize(new Dimension(120, 60));
            // Remove the default styling
            setBorderPainted(false);
            setFocusPainted(false);
            setContentAreaFilled(false);
            setCursor(new Cursor(Cursor.HAND_CURSOR));
            
            // Add a listener to detect when the button is clicked
            addItemListener(e -> {
                startAnimation(e.getStateChange() == ItemEvent.SELECTED);
            });
            
        }
        
        // Method to set the callback function that updates the status label
        public void setStatusUpdateCallback(Runnable callback) {
            this.statusUpdateCallback = callback;
        }
        
        // Method to start the animation when the button state changes
        protected void startAnimation(boolean targetState){
            
            // Stop any existing animation
            if (animationTimer != null && animationTimer.isRunning()) {
                animationTimer.stop();
            }
            
            // Calculate animation parameters
            final float targetProgress = targetState ? 1.0f : 0.0f;
            final float startProgress = animationProgress;
            final float progressStep = (targetProgress - startProgress) / ANIMATION_STEPS;
            final int delay = ANIMATION_DURATION / ANIMATION_STEPS;
            
            // Create a new timer for the animation
            animationTimer = new Timer(delay, null);
            animationTimer.addActionListener(new ActionListener() {
                
                private int currentStep = 0;
                
                @Override
                public void actionPerformed(ActionEvent e) {
                
                    currentStep++;
                    
                     if (currentStep <= ANIMATION_STEPS) {
                         
                        animationProgress = startProgress + (progressStep * currentStep);
                        repaint();
                         
                     }
                     else{
                        animationProgress = targetProgress;
                        animationTimer.stop();
                         if (statusUpdateCallback != null) {
                            statusUpdateCallback.run(targetState);
                        }
                     }
                    
                }
                
            });
            
            // Start the animation timer
            animationTimer.start();
            
        }
        
        // Interface for the status update callback
        public interface Runnable {
            void run(boolean isOn);
        }
        
    }
    
    
    // Neon-style toggle button implementation
    private class NeonToggleButton extends BaseToggleButton {
        
        @Override
        protected void paintComponent(Graphics g) {
            
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            // Define colors for OFF and ON states
            Color bgOffColor = new Color(51, 51, 51);
            Color bgOnColor = new Color(0, 255, 136);
            Color currentBgColor = interpolateColor(bgOffColor, bgOnColor, animationProgress);
            
            // Draw the rounded rectangle background
            g2.setColor(currentBgColor);
            g2.fill(new RoundRectangle2D.Float(0, 0, getWidth(), getHeight(), 60, 60));
            
            // Draw the white circle that moves
            g2.setColor(Color.WHITE);
            int diameter = getHeight() - 8;
            float offX = 4;
            float onX = getWidth() - diameter - 4;
            float currentX = offX + (onX - offX) * animationProgress;
            g2.fillOval(Math.round(currentX), 4, diameter, diameter);
            
            // Add glow effect that increases with animation progress
            int alpha = Math.round(50 * animationProgress);
            if (alpha > 0) {
                g2.setColor(new Color(0, 255, 136, alpha));
                g2.setStroke(new BasicStroke(6));
                g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 60, 60);
            }
            
            g2.dispose();
            
        }
        
    }
    
    
   // Gradient-style toggle button implementation
    private class GradientToggleButton extends BaseToggleButton {
        
        @Override
        protected void paintComponent(Graphics g) {
            
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            // Define colors for OFF and ON states
            Color offStartColor = new Color(255, 107, 107);
            Color offEndColor = new Color(254, 202, 87);
            Color onStartColor = new Color(72, 52, 212);
            Color onEndColor = new Color(104, 109, 224);
            
            // Calculate the current colors based on animation progress
            Color currentStartColor = interpolateColor(offStartColor, onStartColor, animationProgress);
            Color currentEndColor = interpolateColor(offEndColor, onEndColor, animationProgress);
            
            // Create a gradient and apply it
            GradientPaint gradient = new GradientPaint(0, 0, currentStartColor,
                                      getWidth(), getHeight(), currentEndColor);
            g2.setPaint(gradient);
            g2.fill(new RoundRectangle2D.Float(0, 0, getWidth(), getHeight(), 60, 60));
            
            // Draw the white circle that moves
            g2.setColor(Color.WHITE);
            int diameter = getHeight() - 8;
            float offX = 4;
            float onX = getWidth() - diameter - 4;
            float currentX = offX + (onX - offX) * animationProgress;
            g2.fillOval(Math.round(currentX), 4, diameter, diameter);
            
            g2.dispose();
        }
        
    }
    
    
     // Minimal-style toggle button implementation
     private class MinimalToggleButton extends BaseToggleButton {  
         
         @Override
         protected void paintComponent(Graphics g) {
             
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            // Define colors for OFF and ON states
            Color offColor = Color.WHITE;
            Color onColor = new Color(0, 255, 136);
            Color currentColor = interpolateColor(offColor, onColor, animationProgress); 
            
            // Draw the border of the toggle button
            g2.setColor(currentColor);
            g2.setStroke(new BasicStroke(3));
            g2.draw(new RoundRectangle2D.Float(1, 1, getWidth() - 3, getHeight() - 3, 60, 60));
            
            // Draw the circle that moves
            g2.setColor(currentColor);
            int diameter = getHeight() - 12;
            float offX = 6;
            float onX = getWidth() - diameter - 6;
            float currentX = offX + (onX - offX) * animationProgress;
            g2.fillOval(Math.round(currentX), 6, diameter, diameter);
            
            g2.dispose();
            
         }
         
     }
    
    
     
     // Cyberpunk-style toggle button implementation
     private class CyberpunkToggleButton extends BaseToggleButton {
         
         @Override
         protected void paintComponent(Graphics g) {
             
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            // Draw the dark background with less rounded corners
            g2.setColor(new Color(45, 52, 54));
            g2.fill(new RoundRectangle2D.Float(0, 0, getWidth(), getHeight(), 10, 10));
            
             // Define colors for OFF and ON states
            Color offColor = new Color(255, 0, 255); // Magenta
            Color onColor = new Color(0, 255, 255);  // Cyan
            Color currentColor = interpolateColor(offColor, onColor, animationProgress);
            
             // Draw a thin border around the toggle
            g2.setColor(currentColor);
            g2.setStroke(new BasicStroke(2));
            g2.draw(new RoundRectangle2D.Float(1, 1, getWidth() - 3, getHeight() - 3, 10, 10));
            
            // Create a gradient for the slider
            GradientPaint gradient = new GradientPaint(0, 0, new Color(255, 0, 255),
                                      getWidth(), getHeight(), new Color(0, 255, 255));
            g2.setPaint(gradient);
            
            // Draw the slider as a rounded rectangle
            float offX = 4;
            float onX = getWidth() - 52;
            float currentX = offX + (onX - offX) * animationProgress;
            g2.fill(new RoundRectangle2D.Float(currentX, 4, 48, getHeight() - 8, 5, 5));
            
            g2.dispose();
             
         }
         
     }
     
     
     // Neumorphic-style toggle button implementation
     private class NeumorphicToggleButton extends BaseToggleButton {
         
         @Override
         protected void paintComponent(Graphics g) {
             
            Graphics2D g2 = (Graphics2D) g.create();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            // Store dimensions
            int width = getWidth();
            int height = getHeight();
            int cornerRadius = 60;
            
            // Define colors for the neumorphic effect
            Color baseColor = new Color(26, 26, 26);
            Color lightShadow = new Color(40, 40, 40);
            Color darkShadow = new Color(10, 10, 10);
            
            // Draw the base shape
            g2.setColor(baseColor);
            g2.fill(new RoundRectangle2D.Float(0, 0, width, height, cornerRadius, cornerRadius));
            
            // Draw the lighter edge on top-left
            g2.setColor(lightShadow);
            g2.setStroke(new BasicStroke(2f));
            g2.draw(new RoundRectangle2D.Float(1, 1, width-2, height-2, cornerRadius, cornerRadius));
            
            // Draw the darker edge on bottom-right
            g2.setColor(darkShadow);
            g2.setStroke(new BasicStroke(2f));
            g2.draw(new RoundRectangle2D.Float(3, 3, width-6, height-6, cornerRadius, cornerRadius));
            
            // Draw the inner background
            g2.setColor(new Color(22, 22, 22));
            g2.fill(new RoundRectangle2D.Float(4, 4, width-8, height-8, cornerRadius-8, cornerRadius-8));
            
            // Define colors for OFF and ON states
            Color offStartColor = new Color(30, 30, 30);
            Color offEndColor = new Color(34, 34, 34);
            Color onStartColor = new Color(0, 255, 136);
            Color onEndColor = new Color(0, 204, 106);
            
            // Calculate the current colors based on animation progress
            Color currentStartColor = interpolateColor(offStartColor, onStartColor, animationProgress);
            Color currentEndColor = interpolateColor(offEndColor, onEndColor, animationProgress);
            
            // Create a gradient and apply it
            GradientPaint gradient = new GradientPaint(0, 0, currentStartColor,
                                      width, height, currentEndColor);
            
            // Position and draw the toggle circle
            g2.setPaint(gradient);
            int diameter = height - 16;
            float offX = 8;
            float onX = width - diameter - 8;
            float currentX = offX + (onX - offX) * animationProgress;
            
            // Draw the circle shadow with slight offset
            g2.setColor(darkShadow);
            g2.fillOval(Math.round(currentX)+2, 6, diameter, diameter);
            
            // Draw the main circle with gradient
            g2.setPaint(gradient);
            g2.fillOval(Math.round(currentX), 8, diameter, diameter);
            
            // Add highlight to the circle
            g2.setColor(new Color(255, 255, 255, 30));
            g2.fillArc(Math.round(currentX), 8, diameter, diameter, 45, 180);
            
            g2.dispose();
             
         }
         
     }
     
     
     
     
    // Method to blend between two colors based on a ratio (0.0 to 1.0)
    private Color interpolateColor(Color c1, Color c2, float ratio) {
        
        int red = Math.round(c1.getRed() * (1 - ratio) + c2.getRed() * ratio);
        int green = Math.round(c1.getGreen() * (1 - ratio) + c2.getGreen() * ratio);
        int blue = Math.round(c1.getBlue() * (1 - ratio) + c2.getBlue() * ratio);
        
        return new Color(red, green, blue);
        
    }
    
    
    
    public static void main(String[] args) {
     
        SwingUtilities.invokeLater(() ->{
        
          try {
                // Set the application's look and feel to match the OS
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace();
            }
          
          // Create and display the frame
          new ModernToggleButtons().setVisible(true);
            
        });
        
    }
    
}


  


The Final Result:



Modern Toggle Buttons in Java Swing (OFF)

Modern Toggle Buttons in Java Swing (ON)