package com.fine.component.popup; import com.fine.theme.utils.FineUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.Animator; import com.formdev.flatlaf.util.CubicBezierEasing; import com.formdev.flatlaf.util.UIScale; import net.miginfocom.swing.MigLayout; import javax.swing.JPanel; import java.awt.AlphaComposite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.util.Stack; /** * 遮罩功能:渐显遮罩层 * * @author Levy.Xie * @since 12.0 * Created on 2024/12/12 */ public class ComponentLayer extends JPanel { private GlassPaneChild component; private GlassPaneChild nextComponent; private Animator animator; private float animate; private boolean showSnapshot; private boolean simpleSnapshot; private Image image; private Image nextImage; private Stack componentStack; private boolean push; private void pushStack(GlassPaneChild component) { if (componentStack == null) { componentStack = new Stack<>(); } componentStack.push(component); } public ComponentLayer(GlassPaneChild component) { this.component = component; init(); } private void init() { MigLayout layout = new MigLayout("insets 0,fill", "fill", "fill"); setLayout(layout); if (component.getRoundBorder() > 0) { setOpaque(false); component.setOpaque(false); } add(component); component.setVisible(false); } private void initAnimator() { animator = new Animator(350, new Animator.TimingTarget() { @Override public void timingEvent(float v) { animate = v; repaint(); } @Override public void begin() { nextImage = FineUIUtils.createImage(nextComponent); } @Override public void end() { showSnapshot = false; component = nextComponent; component.popupShow(); nextComponent = null; animate = 0; component.setVisible(true); if (nextImage != null) { nextImage.flush(); } } }); animator.setInterpolator(CubicBezierEasing.EASE); } private void startAnimate() { if (animator == null) { initAnimator(); } if (animator.isRunning()) { animator.stop(); } animate = 0; animator.start(); } /** * 放入组件 * * @param component 组件 */ public void pushComponent(GlassPaneChild component) { component.onPush(); pushStack(this.component); push = true; showComponent(component); } /** * 弹出组件 */ public void popComponent() { if (!componentStack.isEmpty()) { GlassPaneChild component = componentStack.pop(); component.onPop(); push = false; showComponent(component); } } private void showComponent(GlassPaneChild component) { showSnapshot = true; this.nextComponent = component; if (!component.isTransparent()) { image = FineUIUtils.createImage(this.component); } if (component.getRoundBorder() > 0) { setOpaque(false); component.setOpaque(false); } component.setVisible(false); remove(this.component); add(component); revalidate(); startAnimate(); } /** * 显示遮罩 */ public void showSnapshot() { if (animator != null && animator.isRunning()) { animator.stop(); } simpleSnapshot = true; doLayout(); if (!component.isTransparent()) { image = FineUIUtils.createImage(component, component.getRoundBorder()); } component.setVisible(false); } /** * 隐藏遮罩 */ public void hideSnapshot() { showSnapshot = false; simpleSnapshot = false; component.setVisible(true); if (image != null) { image.flush(); } } @Override protected void paintComponent(Graphics g) { if (!component.isTransparent()) { if (!isOpaque() && component.getRoundBorder() > 0) { Graphics2D g2 = (Graphics2D) g.create(); FlatUIUtils.setRenderingHints(g2); g2.setColor(getBackground()); int arc = UIScale.scale(component.getRoundBorder()); FlatUIUtils.paintComponentBackground(g2, 0, 0, getWidth(), getHeight(), 0, arc); g2.dispose(); } } super.paintComponent(g); } @Override public void paint(Graphics g) { if (simpleSnapshot) { g.drawImage(image, 0, 0, null); } else if (showSnapshot) { int width = getWidth(); int height = getHeight(); if (width > 0 && height > 0) { BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = bufferedImage.createGraphics(); FlatUIUtils.setRenderingHints(g2); int arc = UIScale.scale(component.getRoundBorder()); g2.setColor(getBackground()); FlatUIUtils.paintComponentBackground(g2, 0, 0, width, height, 0, arc); if (image != null) { paintImage(g2); } if (nextImage != null) { paintNextImage(g2); } g2.dispose(); g.drawImage(bufferedImage, 0, 0, null); } } else { super.paint(g); } } private void paintNextImage(Graphics2D g2) { int w = nextImage.getWidth(null); double x; if (push) { x = getWidth() - (w * animate); } else { x = -getWidth() + (w * animate); } g2.setComposite(AlphaComposite.SrcAtop.derive(animate)); g2.drawImage(nextImage, (int) x, 0, null); } private void paintImage(Graphics2D g2) { int w = image.getWidth(null); double x; if (push) { x = -w * animate; } else { x = w * animate; } g2.setComposite(AlphaComposite.SrcAtop.derive(1f - animate)); g2.drawImage(image, (int) x, 0, null); } public GlassPaneChild getComponent() { return component; } }