Conversation
|
感觉改之后很多地方没有足够的空间显示阴影,看着很奇怪。 |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the hover animation logic by moving it from RipplerContainer to JFXRippler, introducing a hoverOverlay rectangle and implementing mouse event handlers for background interpolation. The review feedback recommends using Animation or Timeline instead of Transition to prevent visual jumps during rapid mouse movements and suggests simplifying the interpolateBackground method for better efficiency.
| protected RippleGenerator rippler; | ||
| protected Pane ripplerPane; | ||
| protected Node control; | ||
| private Transition coverAnimation; |
| mouseEventHandler = event -> { | ||
| if (coverAnimation != null) { | ||
| coverAnimation.stop(); | ||
| coverAnimation = null; | ||
| } | ||
|
|
||
| if (event.getEventType() == MouseEvent.MOUSE_ENTERED) { | ||
| coverAnimation = new Transition() { | ||
| { | ||
| setCycleDuration(Motion.SHORT4); | ||
| setInterpolator(Motion.EASE_IN); | ||
| } | ||
|
|
||
| @Override | ||
| protected void interpolate(double frac) { | ||
| interpolateBackground(frac); | ||
| } | ||
| }; | ||
| } else { | ||
| coverAnimation = new Transition() { | ||
| { | ||
| setCycleDuration(Motion.SHORT4); | ||
| setInterpolator(Motion.EASE_OUT); | ||
| } | ||
|
|
||
| @Override | ||
| protected void interpolate(double frac) { | ||
| interpolateBackground(1 - frac); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| coverAnimation.play(); | ||
| }; |
There was a problem hiding this comment.
目前的动画实现方式在鼠标快速移入移出时会产生明显的跳变。这是因为每次事件都会创建一个新的 Transition,并且动画总是从固定的起始值(0 或 1)开始,而没有考虑当前的透明度状态。建议改用 Timeline 并直接对 hoverOverlay 的 opacityProperty 进行动画处理,这样 JavaFX 会自动从当前值开始平滑过渡,同时也能减少对象的频繁创建。
mouseEventHandler = event -> {
if (coverAnimation != null) {
coverAnimation.stop();
}
boolean isEntered = event.getEventType() == MouseEvent.MOUSE_ENTERED;
Color onSurface = Themes.getColorScheme().getOnSurface();
hoverOverlay.setFill(Color.color(onSurface.getRed(), onSurface.getGreen(), onSurface.getBlue(), 0.04));
coverAnimation = new Timeline(new KeyFrame(Motion.SHORT4,
new KeyValue(hoverOverlay.opacityProperty(), isEntered ? 1 : 0, isEntered ? Motion.EASE_IN : Motion.EASE_OUT)));
coverAnimation.play();
};| private void interpolateBackground(double frac) { | ||
| if (hoverOverlay == null) return; | ||
| if (frac < 0.01) { | ||
| hoverOverlay.setOpacity(0); | ||
| return; | ||
| } | ||
| Color onSurface = Themes.getColorScheme().getOnSurface(); | ||
| Color fillColor = Color.color(onSurface.getRed(), onSurface.getGreen(), onSurface.getBlue(), frac * 0.04); | ||
| hoverOverlay.setFill(fillColor); | ||
| hoverOverlay.setOpacity(1); | ||
| } |
There was a problem hiding this comment.
简化 interpolateBackground 方法。如果采用动画化 opacityProperty 的方案,此方法只需负责设置填充颜色和最终的透明度即可。这不仅使代码更简洁,也提高了渲染效率。
private void interpolateBackground(double frac) {
if (hoverOverlay == null) return;
Color onSurface = Themes.getColorScheme().getOnSurface();
hoverOverlay.setFill(Color.color(onSurface.getRed(), onSurface.getGreen(), onSurface.getBlue(), 0.04));
hoverOverlay.setOpacity(frac);
}|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b3d2410e06
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| hoverOverlay.setY(bounds.getMinY() + diffMinY - snappedTopInset()); | ||
| hoverOverlay.setWidth(control.getLayoutBounds().getWidth()); | ||
| hoverOverlay.setHeight(control.getLayoutBounds().getHeight()); | ||
| hoverOverlay.setClip(getMask()); |
There was a problem hiding this comment.
Reuse hover clip instead of recreating bound masks
resetRippler() now calls hoverOverlay.setClip(getMask()) on every layout/bounds update, which repeatedly allocates new mask nodes during normal relayout (window resize, cell reuse, etc.). Several getMask() overrides create bound properties (e.g. JFXButtonSkin#getMask binds shapeProperty and backgroundProperty), so replacing the clip without unbinding the old mask accumulates listeners and retained nodes over time. Before this change, getMask() was not invoked on every reset path, so this introduces an unbounded memory/perf regression in heavily relaid-out views.
Useful? React with 👍 / 👎.
放在 JFXRippler 中实现 JFXButton 等 JFoenix 控件也能有悬停效果