Таким образом, при решении этих проблем обычно лучше уменьшить количество Timer
, которое у вас есть, так как каждый таймер будет отправлять несколько событий в очередь диспетчеризации событий (там есть собственные обновления галочек, а также перекрашивать события). Вся эта деятельность может снизить производительность системы.
Анимация также является иллюзией изменений во времени, с этой целью, а не для того, чтобы попытаться зациклиться от начальной точки до конечной точки, вы должны решить, как долго вы хотите, чтобы анимация запускалась и вычисляли ход времени и обновить значения соответственно (это больше из цикла анимации на основе временной шкалы). Это может помочь уменьшить появление «отстающих»
Обычно я использовать Timing Framework для достижения этой цели, но вы также можете взглянуть на Trident рамки или Universal Tween Engine которые также обеспечивают комплексную поддержку анимации для Swing.
Этот пример очень плотно связан с его целью. Лично я обычно имел абстрактную концепцию «аниматируемого» объекта, который, вероятно, имел бы только метод update(float)
, который затем был бы расширен, чтобы поддерживать другие объекты, но я оставлю это вам в орех.
Еще одна проблема - убедиться, что компонент полностью прозрачен для начала (setOpaque(false)
), что позволяет нам подделывать полупрозрачность компонента во время анимации.
Как правило, я всегда рекомендую вам переопределить paintComponent
, но есть несколько раз, когда это не подходит, это один из них. В принципе, чтобы облегчить переход от одного компонента к другому, нам нужно контролировать альфа-уровень ВСЕХ дочерних компонентов внутри компонента, это когда переопределение paint
будет лучшим выбором.
![Fade](https://i.stack.imgur.com/yuF4z.gif)
нб: Код устанавливается для запуска на отметке 25fps, но программа для захвата снимков экрана на примерно 8fps
import java.awt.AlphaComposite;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FadeTest {
public static void main(String[] args) {
new FadeTest();
}
public FadeTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
BufferedImage img1 = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\Ponies\\sillydash-small.png"));
BufferedImage img2 = ImageIO.read(new File("C:\\Users\\shane\\Dropbox\\Ponies\\SmallPony.png"));
AlphaPane pane1 = new AlphaPane();
pane1.add(new JLabel(new ImageIcon(img1)));
pane1.setAlpha(1f);
AlphaPane pane2 = new AlphaPane();
pane2.add(new JLabel(new ImageIcon(img2)));
pane2.setAlpha(0f);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
frame.add(pane1, gbc);
frame.add(pane2, gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
MouseAdapter ma = new MouseAdapter() {
private AnimationController controller;
@Override
public void mouseClicked(MouseEvent e) {
try {
if (controller != null) {
controller.stop();
}
controller = new AnimationController(4000);
boolean fadeIn = pane1.getAlpha() < pane2.getAlpha();
controller.add(controller.new AlphaRange(pane1, fadeIn));
controller.add(controller.new AlphaRange(pane2, !fadeIn));
controller.start();
} catch (InvalidStateException ex) {
ex.printStackTrace();
}
}
};
pane1.addMouseListener(ma);
pane2.addMouseListener(ma);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public class AnimationController {
private List<AlphaRange> animationRanges;
private Timer timer;
private Long startTime;
private long runTime;
public AnimationController(int runTime) {
this.runTime = runTime;
animationRanges = new ArrayList<>(25);
}
public void add(AlphaRange range) {
animationRanges.add(range);
}
public void start() throws InvalidStateException {
if (timer == null || !timer.isRunning()) {
timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (startTime == null) {
startTime = System.currentTimeMillis();
}
long duration = System.currentTimeMillis() - startTime;
float progress = (float) duration/(float) runTime;
if (progress > 1f) {
progress = 1f;
stop();
}
System.out.println(NumberFormat.getPercentInstance().format(progress));
for (AlphaRange range : animationRanges) {
range.update(progress);
}
}
});
timer.start();
} else {
throw new InvalidStateException("Animation is running");
}
}
public void stop() {
if (timer != null) {
timer.stop();
}
}
public class AlphaRange {
private float from;
private float to;
private AlphaPane alphaPane;
public AlphaRange(AlphaPane alphaPane, boolean fadeIn) {
this.from = alphaPane.getAlpha();
this.to = fadeIn ? 1f : 0f;
this.alphaPane = alphaPane;
}
public float getFrom() {
return from;
}
public float getTo() {
return to;
}
public float getValueBasedOnProgress(float progress) {
float value = 0;
float distance = to - from;
value = (distance * progress);
value += from;
return value;
}
public void update(float progress) {
float alpha = getValueBasedOnProgress(progress);
alphaPane.setAlpha(alpha);
}
}
}
public class InvalidStateException extends Exception {
public InvalidStateException(String message) {
super(message);
}
public InvalidStateException(String message, Throwable cause) {
super(message, cause);
}
}
public class AlphaPane extends JPanel {
private float alpha;
public AlphaPane() {
setOpaque(false);
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
super.paint(g2d);
g2d.dispose();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Fake the background
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
public void setAlpha(float value) {
if (alpha != value) {
this.alpha = Math.min(1f, Math.max(0, value));
repaint();
}
}
public float getAlpha() {
return alpha;
}
}
}
Возможный дубликат [этот вопрос] (HTTP://stackoverflow.com/questions/22275435/cardlayout-showing-two-panels-flashing). Пожалуйста, см. Мой ответ, поскольку я думаю, что это может вам помочь. –