现在,可能有几种方法可以做到这一点,但这基本上是我想出的......
首先,我创建了一个自定义标签,它使用javax.swing.Timer 从起始 alpha 值前进到目标 alpha 值(即 0-1 淡入)。
在这个标签上,我添加了一个简单的waitFor 方法,它一直等到达到目标值。这是通过一个简单的对象监视器来实现的。非常重要,切勿在事件调度线程上调用此方法...
接下来,我创建了一系列带有我想要显示的文本的标签,并将每个标签添加到输出中。
然后我开始一个单独的Thread 并迭代列表,淡入每个标签并使用waitFor 等待它显示...
import java.awt.AlphaComposite;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FadingLabels {
public static void main(String[] args) {
new FadingLabels();
}
public FadingLabels() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
final List<FadingLabel> labels = new ArrayList<>(25);
labels.add(new FadingLabel("A "));
labels.add(new FadingLabel("long "));
labels.add(new FadingLabel("time "));
labels.add(new FadingLabel("ago "));
labels.add(new FadingLabel("in "));
labels.add(new FadingLabel("a "));
labels.add(new FadingLabel("galaxy "));
labels.add(new FadingLabel("far, "));
labels.add(new FadingLabel("far, "));
labels.add(new FadingLabel("away"));
labels.add(new FadingLabel("..."));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
for (FadingLabel label : labels) {
frame.add(label);
}
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
new Thread(new Runnable() {
@Override
public void run() {
for (FadingLabel label : labels) {
label.fadeIn();
label.waitFor();
}
}
}).start();
}
});
}
public class FadingLabel extends JLabel {
protected static final int TIME = 1000;
protected final Object fadeLock = new Object();
private float targetAlpha;
private float alpha = 0;
private Timer timer;
private long startTime;
private float fromAlpha;
public FadingLabel() {
init();
}
public FadingLabel(String text, Icon icon, int horizontalAlignment) {
super(text, icon, horizontalAlignment);
init();
}
public FadingLabel(String text, int horizontalAlignment) {
super(text, horizontalAlignment);
init();
}
public FadingLabel(String text) {
super(text);
init();
}
public FadingLabel(Icon image, int horizontalAlignment) {
super(image, horizontalAlignment);
init();
}
public FadingLabel(Icon image) {
super(image);
init();
}
protected void init() {
timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (alpha < 1f) {
long now = System.currentTimeMillis();
long diff = now - startTime;
float progress = (float) diff / (float) TIME;
float distance = targetAlpha - fromAlpha;
alpha = (float) (distance * progress);
alpha += fromAlpha;
if (alpha > 1f) {
timer.stop();
alpha = 1f;
}
} else {
alpha = 1f;
timer.stop();
}
repaint();
if (!timer.isRunning()) {
synchronized (fadeLock) {
fadeLock.notifyAll();
}
}
}
});
timer.setInitialDelay(0);
}
protected void fadeTo(float target) {
Runnable run = new Runnable() {
@Override
public void run() {
timer.stop();
fromAlpha = alpha;
targetAlpha = target;
if (targetAlpha != alpha) {
startTime = System.currentTimeMillis();
timer.start();
} else {
repaint();
}
}
};
if (EventQueue.isDispatchThread()) {
run.run();
} else {
EventQueue.invokeLater(run);
}
}
public void fadeIn() {
fadeTo(1f);
}
public void fadeOut() {
fadeTo(0f);
}
public void waitFor() {
if (EventQueue.isDispatchThread()) {
throw new IllegalStateException("Calling waitFor while within the EDT!");
}
synchronized (fadeLock) {
try {
fadeLock.wait();
} catch (InterruptedException ex) {
}
}
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
super.paint(g2d);
g2d.dispose();
}
}
}
动画部分使用固定的时间进度,而不是固定的增量。这允许动画根据操作系统可能发生的开销而更加可变。基本上这意味着动画每次都会在固定的时间段内进行