Summary

JToggleButtonに選択するとアニメーション効果付きで時計回りに90度回転、選択解除で-90度回転して元の0度に戻る展開・折り畳みIconを設定します。

Source Code Examples

class AnimatableIcon implements Icon {
  private final Icon icon;
  private final Timer timer = new Timer(15, null);
  private double currentAngle;
  private double targetAngle;
  private Component parent;

  protected AnimatableIcon(Icon icon, Component parent) {
    this.icon = icon;
    this.parent = parent;
    double step = .5;
    this.timer.addActionListener(e -> {
      double diff = targetAngle - currentAngle;
      if (Math.abs(diff) < step) {
        currentAngle = targetAngle;
        timer.stop();
      } else {
        currentAngle += diff * step;
      }
      Optional.ofNullable(this.parent).ifPresent(Component::repaint);
    });
  }

  public void animateTo(double angle) {
    this.targetAngle = angle;
    if (!timer.isRunning()) {
      timer.start();
    }
  }

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    if (this.parent == null) {
      this.parent = c;
    }
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    int cx = x + icon.getIconWidth() / 2;
    int cy = y + icon.getIconHeight() / 2;
    g2.rotate(Math.toRadians(currentAngle), cx, cy);
    icon.paintIcon(c, g2, x, y);
    g2.dispose();
  }

  @Override public int getIconWidth() {
    return icon.getIconWidth();
  }

  @Override public int getIconHeight() {
    return icon.getIconHeight();
  }
}
View in GitHub: Java, Kotlin

Description

  • 折り畳み状態の右矢印アイコンはMenu.arrowIconを使用
  • アコーディオンパネルはJPanelをアコーディオン風に展開のタイトル部分をJLabelからBoxLayoutを設定したJButtonに変更して使用
    • JButtonの子要素として左端にタイトル文字列表示用のJLabel、右端に展開・折り畳みIconを設定したJToggleButtonを配置
  • JButton、またはその子要素のJToggleButtonがクリックされたらアコーディオンパネルの展開・折り畳みと合わせて展開・折り畳みIconの回転角度を設定してアニメーションを開始
private void rotate(AnimatableIcon animeIcon) {
  if (toggleButton.isSelected()) {
    animeIcon.animateTo(90d);
    panel.setVisible(true);
  } else {
    animeIcon.animateTo(0d);
    panel.setVisible(false);
  }
  revalidate();
  EventQueue.invokeLater(() -> panel.scrollRectToVisible(panel.getBounds()));
}

Reference

Comment