From 0939ed819e10f77c33feca23fffec6717249a975 Mon Sep 17 00:00:00 2001 From: Yuhui Huang Date: Mon, 2 Aug 2021 16:46:45 +0800 Subject: [PATCH] feat: title bar swipe animation. --- .../ui/animation/ContainerAnimations.java | 44 ++++++++++++++++++- .../hmcl/ui/construct/Navigator.java | 19 +++++--- .../hmcl/ui/decorator/Decorator.java | 11 +++++ .../ui/decorator/DecoratorController.java | 2 + .../hmcl/ui/decorator/DecoratorSkin.java | 13 +++++- .../hmcl/ui/decorator/DecoratorTabPage.java | 5 ++- 6 files changed, 84 insertions(+), 10 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/ContainerAnimations.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/ContainerAnimations.java index 5c423389a..20bca631d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/ContainerAnimations.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/ContainerAnimations.java @@ -173,7 +173,49 @@ public enum ContainerAnimations { new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH)), new KeyFrame(c.getDuration(), new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH), - new KeyValue(c.getPreviousNode().translateXProperty(), c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH)))); + new KeyValue(c.getPreviousNode().translateXProperty(), c.getCurrentRoot().getWidth(), Interpolator.EASE_BOTH)))), + + SWIPE_LEFT_FADE_SHORT(c -> { + c.getPreviousNode().setScaleX(1); + c.getPreviousNode().setScaleY(1); + c.getPreviousNode().setOpacity(0); + c.getPreviousNode().setTranslateX(0); + c.getCurrentNode().setScaleX(1); + c.getCurrentNode().setScaleY(1); + c.getCurrentNode().setOpacity(1); + c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth()); + }, c -> + Arrays.asList(new KeyFrame(Duration.ZERO, + new KeyValue(c.getCurrentNode().translateXProperty(), 50, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(c.getCurrentNode().opacityProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().opacityProperty(), 1, Interpolator.EASE_BOTH)), + new KeyFrame(c.getDuration(), + new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().translateXProperty(), -50, Interpolator.EASE_BOTH), + new KeyValue(c.getCurrentNode().opacityProperty(), 1, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)))), + + SWIPE_RIGHT_FADE_SHORT(c -> { + c.getPreviousNode().setScaleX(1); + c.getPreviousNode().setScaleY(1); + c.getPreviousNode().setOpacity(0); + c.getPreviousNode().setTranslateX(0); + c.getCurrentNode().setScaleX(1); + c.getCurrentNode().setScaleY(1); + c.getCurrentNode().setOpacity(1); + c.getCurrentNode().setTranslateX(c.getCurrentRoot().getWidth()); + }, c -> + Arrays.asList(new KeyFrame(Duration.ZERO, + new KeyValue(c.getCurrentNode().translateXProperty(), -50, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(c.getCurrentNode().opacityProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().opacityProperty(), 1, Interpolator.EASE_BOTH)), + new KeyFrame(c.getDuration(), + new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().translateXProperty(), 50, Interpolator.EASE_BOTH), + new KeyValue(c.getCurrentNode().opacityProperty(), 1, Interpolator.EASE_BOTH), + new KeyValue(c.getPreviousNode().opacityProperty(), 0, Interpolator.EASE_BOTH)))); private final AnimationProducer animationProducer; private ContainerAnimations opposite; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java index 4cdfb567f..d2c9a20ba 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java @@ -30,6 +30,7 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.animation.AnimationProducer; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.animation.TransitionPane; +import org.jackhuang.hmcl.ui.wizard.Navigation; import org.jackhuang.hmcl.util.Logging; import java.util.Optional; @@ -48,7 +49,7 @@ public class Navigator extends TransitionPane { backable.set(canGoBack()); getChildren().setAll(init); - fireEvent(new NavigationEvent(this, init, NavigationEvent.NAVIGATED)); + fireEvent(new NavigationEvent(this, init, Navigation.NavigationDirection.START, NavigationEvent.NAVIGATED)); initialized = true; } @@ -68,14 +69,14 @@ public class Navigator extends TransitionPane { stack.push(node); backable.set(canGoBack()); - NavigationEvent navigating = new NavigationEvent(this, from, NavigationEvent.NAVIGATING); + NavigationEvent navigating = new NavigationEvent(this, from, Navigation.NavigationDirection.NEXT, NavigationEvent.NAVIGATING); fireEvent(navigating); node.fireEvent(navigating); node.getProperties().put("hmcl.navigator.animation", animationProducer); setContent(node, animationProducer); - NavigationEvent navigated = new NavigationEvent(this, node, NavigationEvent.NAVIGATED); + NavigationEvent navigated = new NavigationEvent(this, node, Navigation.NavigationDirection.NEXT, NavigationEvent.NAVIGATED); node.fireEvent(navigated); EventHandler handler = event -> close(node); @@ -111,7 +112,7 @@ public class Navigator extends TransitionPane { backable.set(canGoBack()); Node node = stack.peek(); - NavigationEvent navigating = new NavigationEvent(this, from, NavigationEvent.NAVIGATING); + NavigationEvent navigating = new NavigationEvent(this, from, Navigation.NavigationDirection.PREVIOUS, NavigationEvent.NAVIGATING); fireEvent(navigating); node.fireEvent(navigating); @@ -122,7 +123,7 @@ public class Navigator extends TransitionPane { setContent(node, ContainerAnimations.NONE.getAnimationProducer()); } - NavigationEvent navigated = new NavigationEvent(this, node, NavigationEvent.NAVIGATED); + NavigationEvent navigated = new NavigationEvent(this, node, Navigation.NavigationDirection.PREVIOUS, NavigationEvent.NAVIGATED); node.fireEvent(navigated); Optional.ofNullable(from.getProperties().get(PROPERTY_DIALOG_CLOSE_HANDLER)) @@ -206,12 +207,14 @@ public class Navigator extends TransitionPane { private final Navigator source; private final Node node; + private final Navigation.NavigationDirection direction; - public NavigationEvent(Navigator source, Node target, EventType eventType) { + public NavigationEvent(Navigator source, Node target, Navigation.NavigationDirection direction, EventType eventType) { super(source, target, eventType); this.source = source; this.node = target; + this.direction = direction; } @Override @@ -222,5 +225,9 @@ public class Navigator extends TransitionPane { public Node getNode() { return node; } + + public Navigation.NavigationDirection getDirection() { + return direction; + } } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java index cc6b89901..99b51448b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java @@ -34,6 +34,7 @@ import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.stage.StageStyle; +import org.jackhuang.hmcl.ui.wizard.Navigation; public class Decorator extends Control { private final ListProperty drawer = new SimpleListProperty<>(FXCollections.observableArrayList()); @@ -51,6 +52,7 @@ public class Decorator extends Control { private final BooleanProperty canClose = new SimpleBooleanProperty(false); private final BooleanProperty showCloseAsHome = new SimpleBooleanProperty(false); private final Stage primaryStage; + private Navigation.NavigationDirection navigationDirection = Navigation.NavigationDirection.START; private StackPane drawerWrapper; private final ReadOnlyBooleanWrapper allowMove = new ReadOnlyBooleanWrapper(); @@ -238,4 +240,13 @@ public class Decorator extends Control { e.consume(); }); } + + // TODO: Dirty implementation. + public Navigation.NavigationDirection getNavigationDirection() { + return navigationDirection; + } + + public void setNavigationDirection(Navigation.NavigationDirection navigationDirection) { + this.navigationDirection = navigationDirection; + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java index d776a256f..934444123 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java @@ -243,6 +243,8 @@ public class DecoratorController { decorator.showCloseAsHomeProperty().set(true); } + decorator.setNavigationDirection(event.getDirection()); + // state property should be updated at last. if (to instanceof DecoratorPage) { decorator.stateProperty().bind(((DecoratorPage) to).stateProperty()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java index 1bbb5071e..94d429dde 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java @@ -41,8 +41,10 @@ import javafx.util.Duration; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; +import org.jackhuang.hmcl.ui.animation.AnimationProducer; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.animation.TransitionPane; +import org.jackhuang.hmcl.ui.wizard.Navigation; import org.jackhuang.hmcl.util.Lang; public class DecoratorSkin extends SkinBase { @@ -165,7 +167,16 @@ public class DecoratorSkin extends SkinBase { Node node = createNavBar(skinnable, s.isTitleBarTransparent(), s.getLeftPaneWidth(), s.isBackable(), skinnable.canCloseProperty().get(), skinnable.showCloseAsHomeProperty().get(), s.isRefreshable(), s.getTitle(), s.getTitleNode()); double targetOpacity = s.isTitleBarTransparent() ? 0 : 1; if (s.isAnimate()) { - navBarPane.setContent(node, ContainerAnimations.FADE.getAnimationProducer()); + AnimationProducer animation; + if (skinnable.getNavigationDirection() == Navigation.NavigationDirection.NEXT) { + animation = ContainerAnimations.SWIPE_LEFT_FADE_SHORT.getAnimationProducer(); + } else if (skinnable.getNavigationDirection() == Navigation.NavigationDirection.PREVIOUS) { + animation = ContainerAnimations.SWIPE_RIGHT_FADE_SHORT.getAnimationProducer(); + } else { + animation = ContainerAnimations.FADE.getAnimationProducer(); + } + skinnable.setNavigationDirection(Navigation.NavigationDirection.START); + navBarPane.setContent(node, animation); } else { navBarPane.getChildren().setAll(node); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTabPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTabPage.java index 7154d808a..07c5e9060 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTabPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTabPage.java @@ -26,6 +26,7 @@ import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.construct.Navigator; import org.jackhuang.hmcl.ui.construct.TabControl; import org.jackhuang.hmcl.ui.construct.TabHeader; +import org.jackhuang.hmcl.ui.wizard.Navigation; public abstract class DecoratorTabPage extends DecoratorTransitionPage implements TabControl { @@ -36,10 +37,10 @@ public abstract class DecoratorTabPage extends DecoratorTransitionPage implement } if (newValue.getNode() != null) { onNavigating(getCurrentPage()); - if (getCurrentPage() != null) getCurrentPage().fireEvent(new Navigator.NavigationEvent(null, getCurrentPage(), Navigator.NavigationEvent.NAVIGATING)); + if (getCurrentPage() != null) getCurrentPage().fireEvent(new Navigator.NavigationEvent(null, getCurrentPage(), Navigation.NavigationDirection.NEXT, Navigator.NavigationEvent.NAVIGATING)); navigate(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer()); onNavigated(getCurrentPage()); - if (getCurrentPage() != null) getCurrentPage().fireEvent(new Navigator.NavigationEvent(null, getCurrentPage(), Navigator.NavigationEvent.NAVIGATED)); + if (getCurrentPage() != null) getCurrentPage().fireEvent(new Navigator.NavigationEvent(null, getCurrentPage(), Navigation.NavigationDirection.NEXT, Navigator.NavigationEvent.NAVIGATED)); } }); }