javaFx清空缓存动画特效

package com.excellent.archimedes.fx.controller;

/**

* @author zhaoyong

* @Date 2024/10/12

* @Description

*/

import com.alibaba.fastjson.JSON;

import com.excellent.archimedes.util.AlertUtils;

import com.excellent.archimedes.util.UIViewContextUtils;

import javafx.animation.*;

import javafx.event.ActionEvent;

import javafx.fxml.FXML;

import javafx.fxml.Initializable;

import javafx.geometry.Point2D;

import javafx.scene.canvas.Canvas;

import javafx.scene.canvas.GraphicsContext;

import javafx.scene.control.Button;

import javafx.scene.layout.Pane;

import javafx.scene.paint.Color;

import javafx.util.Duration;

import org.apache.commons.lang3.StringUtils;

import org.springframework.stereotype.Component;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import java.util.ResourceBundle;

@Component

public class SeeCacheController implements Initializable {

/* ===================== 以下为原控件 ===================== */

@FXML private Pane userPane;

@FXML private Button reset;

@FXML private Button returnHomepage;

/* ===================== 新增动画节点 ===================== */

private Canvas animCanvas; // 360°圆环+碎片

private GraphicsContext gc;

private final double RING_RADIUS = 80; // 圆环半径

private final double RING_STROKE = 6; // 圆环粗细

private final int FRAG_COUNT = 12; // 碎片数量

private final List<Fragment> fragments = new ArrayList<>();

@Override

public void initialize(URL location, ResourceBundle resources) {

/* 把 Canvas 放到原 Pane 里,居中 */

animCanvas = new Canvas(300, 300);

userPane.getChildren().add(animCanvas);

animCanvas.setLayoutX(20); // 自己按实际布局微调

animCanvas.setLayoutY(30);

gc = animCanvas.getGraphicsContext2D();

}

/* ===================== 原业务方法不动 ===================== */

@FXML void returnHome(ActionEvent event) { UIViewContextUtils.subStage.close(); }

@FXML void returnToHome(ActionEvent event) { UIViewContextUtils.subStage.hide(); }

@FXML

void checkCache(ActionEvent event) {

try {

String cacheContent = JSON.toJSONString(UIViewContextUtils.subStage.getUserData());

if (StringUtils.isNotBlank(cacheContent) && !cacheContent.equals("null")) {

AlertUtils.alert("查看缓存", cacheContent);

} else {

AlertUtils.alert("查看缓存", "缓存已清空");

}

} catch (Exception e) {

e.printStackTrace();

}

}

/* ===================== 清空缓存 + 360°特效 ===================== */

@FXML

void clearCache(ActionEvent event) {

boolean go = AlertUtils.prompt("要清空缓存", "确定要清空缓存吗?");

if (!go) return;

initFragments(); // 生成 12 片扇形碎片

Timeline master = new Timeline(new KeyFrame(Duration.millis(16), e -> drawFrame())); // 60 fps

master.setCycleCount(Timeline.INDEFINITE);

master.play();

/* 3 秒后结束动画并真正清理 */

PauseTransition end = new PauseTransition(Duration.seconds(3));

end.setOnFinished(e -> {

master.stop();

fragments.clear();

gc.clearRect(0, 0, animCanvas.getWidth(), animCanvas.getHeight());

UIViewContextUtils.thirdSubStage.setUserData(null);

UIViewContextUtils.subStage.setUserData(null);

UIViewContextUtils.primaryStage.setUserData(null);

AlertUtils.alert("清空缓存", "缓存已清空完毕");

});

end.play();

}

/* ===================== 碎片内部类 ===================== */

private static class Fragment {

double startAngle; // 初始角度

double distance; // 当前已飞出距离

double speed; // 每帧飞出速度

double opacity; // 当前透明度

final double MAX_DIST = 120;

Fragment(double angle) {

this.startAngle = angle;

this.distance = 0;

this.speed = 2 + Math.random() * 2;

this.opacity = 1.0;

}

void fly() {

distance += speed;

opacity = Math.max(0, 1 - distance / MAX_DIST);

}

}

private void initFragments() {

fragments.clear();

for (int i = 0; i < FRAG_COUNT; i++) {

fragments.add(new Fragment(i * 360.0 / FRAG_COUNT));

}

}

/* ===================== 每帧绘制 ===================== */

private double ringAngle = 0;

private void drawFrame() {

gc.clearRect(0, 0, animCanvas.getWidth(), animCanvas.getHeight());

double cx = animCanvas.getWidth() / 2;

double cy = animCanvas.getHeight() / 2;

/* 1. 旋转圆环 */

ringAngle += 4;

gc.save();

gc.translate(cx, cy);

gc.rotate(ringAngle);

gc.setStroke(Color.rgb(30, 144, 255));

gc.setLineWidth(RING_STROKE);

gc.strokeOval(-RING_RADIUS, -RING_RADIUS, RING_RADIUS * 2, RING_RADIUS * 2);

/* 画 60 条刻度 */

for (int i = 0; i < 60; i++) {

double a = Math.toRadians(i * 6);

double len = (i % 5 == 0) ? 10 : 5;

gc.strokeLine(RING_RADIUS - len, 0, RING_RADIUS, 0);

gc.rotate(6);

}

gc.restore();

/* 2. 碎片向外飞 */

gc.setFill(Color.ORANGE);

fragments.removeIf(f -> f.opacity <= 0);

for (Fragment f : fragments) {

double rad = Math.toRadians(f.startAngle);

Point2D p = new Point2D(

cx + Math.cos(rad) * (RING_RADIUS * 0.7 + f.distance),

cy + Math.sin(rad) * (RING_RADIUS * 0.7 + f.distance));

gc.setGlobalAlpha(f.opacity);

gc.fillOval(p.getX() - 4, p.getY() - 4, 8, 8);

f.fly();

}

gc.setGlobalAlpha(1.0);

}

}

相关推荐
万象.14 小时前
redis持久化:AOF和RDB
数据库·redis·缓存
cheungxiongwei.com14 小时前
深入解析 DNS 缓存与 TTL:工作原理、修改生效机制与优化策略
缓存
!chen15 小时前
Redis快速实现布隆过滤器
数据库·redis·缓存
xxxmine16 小时前
Redis 持久化详解:RDB、AOF 与混合模式
数据库·redis·缓存
what丶k17 小时前
SpringBoot3 缓存抽象深度实践:Caffeine+Redis多级缓存,穿透/雪崩/击穿防御全方案
数据库·redis·缓存
咖啡の猫17 小时前
Redis简单介绍
数据库·redis·缓存
爱吃大芒果17 小时前
Flutter for OpenHarmony 实战: mango_shop 购物车模块的状态同步与本地缓存处理
flutter·缓存·dart
源代码•宸19 小时前
Redis 攻略(Redis Object)
数据库·redis·后端·缓存·字符串·哈希表·type
heartbeat..19 小时前
Redis常见问题及对应解决方案(基础+性能+持久化+高可用全场景)
java·数据库·redis·缓存
Marshmallowc20 小时前
强缓存失效了怎么办?深度解析浏览器内存缓存与硬盘缓存的存储逻辑
http·缓存·浏览器原理