feat: title bar swipe animation.

This commit is contained in:
Yuhui Huang 2021-08-02 16:46:45 +08:00
parent 5da4ad7a62
commit 0939ed819e
6 changed files with 84 additions and 10 deletions

View File

@ -173,7 +173,49 @@ public enum ContainerAnimations {
new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH)), new KeyValue(c.getPreviousNode().translateXProperty(), 0, Interpolator.EASE_BOTH)),
new KeyFrame(c.getDuration(), new KeyFrame(c.getDuration(),
new KeyValue(c.getCurrentNode().translateXProperty(), 0, Interpolator.EASE_BOTH), 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 final AnimationProducer animationProducer;
private ContainerAnimations opposite; private ContainerAnimations opposite;

View File

@ -30,6 +30,7 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.animation.AnimationProducer; import org.jackhuang.hmcl.ui.animation.AnimationProducer;
import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.wizard.Navigation;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
import java.util.Optional; import java.util.Optional;
@ -48,7 +49,7 @@ public class Navigator extends TransitionPane {
backable.set(canGoBack()); backable.set(canGoBack());
getChildren().setAll(init); getChildren().setAll(init);
fireEvent(new NavigationEvent(this, init, NavigationEvent.NAVIGATED)); fireEvent(new NavigationEvent(this, init, Navigation.NavigationDirection.START, NavigationEvent.NAVIGATED));
initialized = true; initialized = true;
} }
@ -68,14 +69,14 @@ public class Navigator extends TransitionPane {
stack.push(node); stack.push(node);
backable.set(canGoBack()); backable.set(canGoBack());
NavigationEvent navigating = new NavigationEvent(this, from, NavigationEvent.NAVIGATING); NavigationEvent navigating = new NavigationEvent(this, from, Navigation.NavigationDirection.NEXT, NavigationEvent.NAVIGATING);
fireEvent(navigating); fireEvent(navigating);
node.fireEvent(navigating); node.fireEvent(navigating);
node.getProperties().put("hmcl.navigator.animation", animationProducer); node.getProperties().put("hmcl.navigator.animation", animationProducer);
setContent(node, 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); node.fireEvent(navigated);
EventHandler<PageCloseEvent> handler = event -> close(node); EventHandler<PageCloseEvent> handler = event -> close(node);
@ -111,7 +112,7 @@ public class Navigator extends TransitionPane {
backable.set(canGoBack()); backable.set(canGoBack());
Node node = stack.peek(); 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); fireEvent(navigating);
node.fireEvent(navigating); node.fireEvent(navigating);
@ -122,7 +123,7 @@ public class Navigator extends TransitionPane {
setContent(node, ContainerAnimations.NONE.getAnimationProducer()); 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); node.fireEvent(navigated);
Optional.ofNullable(from.getProperties().get(PROPERTY_DIALOG_CLOSE_HANDLER)) Optional.ofNullable(from.getProperties().get(PROPERTY_DIALOG_CLOSE_HANDLER))
@ -206,12 +207,14 @@ public class Navigator extends TransitionPane {
private final Navigator source; private final Navigator source;
private final Node node; private final Node node;
private final Navigation.NavigationDirection direction;
public NavigationEvent(Navigator source, Node target, EventType<? extends Event> eventType) { public NavigationEvent(Navigator source, Node target, Navigation.NavigationDirection direction, EventType<? extends Event> eventType) {
super(source, target, eventType); super(source, target, eventType);
this.source = source; this.source = source;
this.node = target; this.node = target;
this.direction = direction;
} }
@Override @Override
@ -222,5 +225,9 @@ public class Navigator extends TransitionPane {
public Node getNode() { public Node getNode() {
return node; return node;
} }
public Navigation.NavigationDirection getDirection() {
return direction;
}
} }
} }

View File

@ -34,6 +34,7 @@ import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import org.jackhuang.hmcl.ui.wizard.Navigation;
public class Decorator extends Control { public class Decorator extends Control {
private final ListProperty<Node> drawer = new SimpleListProperty<>(FXCollections.observableArrayList()); private final ListProperty<Node> drawer = new SimpleListProperty<>(FXCollections.observableArrayList());
@ -51,6 +52,7 @@ public class Decorator extends Control {
private final BooleanProperty canClose = new SimpleBooleanProperty(false); private final BooleanProperty canClose = new SimpleBooleanProperty(false);
private final BooleanProperty showCloseAsHome = new SimpleBooleanProperty(false); private final BooleanProperty showCloseAsHome = new SimpleBooleanProperty(false);
private final Stage primaryStage; private final Stage primaryStage;
private Navigation.NavigationDirection navigationDirection = Navigation.NavigationDirection.START;
private StackPane drawerWrapper; private StackPane drawerWrapper;
private final ReadOnlyBooleanWrapper allowMove = new ReadOnlyBooleanWrapper(); private final ReadOnlyBooleanWrapper allowMove = new ReadOnlyBooleanWrapper();
@ -238,4 +240,13 @@ public class Decorator extends Control {
e.consume(); e.consume();
}); });
} }
// TODO: Dirty implementation.
public Navigation.NavigationDirection getNavigationDirection() {
return navigationDirection;
}
public void setNavigationDirection(Navigation.NavigationDirection navigationDirection) {
this.navigationDirection = navigationDirection;
}
} }

View File

@ -243,6 +243,8 @@ public class DecoratorController {
decorator.showCloseAsHomeProperty().set(true); decorator.showCloseAsHomeProperty().set(true);
} }
decorator.setNavigationDirection(event.getDirection());
// state property should be updated at last. // state property should be updated at last.
if (to instanceof DecoratorPage) { if (to instanceof DecoratorPage) {
decorator.stateProperty().bind(((DecoratorPage) to).stateProperty()); decorator.stateProperty().bind(((DecoratorPage) to).stateProperty());

View File

@ -41,8 +41,10 @@ import javafx.util.Duration;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; 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.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.wizard.Navigation;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
public class DecoratorSkin extends SkinBase<Decorator> { public class DecoratorSkin extends SkinBase<Decorator> {
@ -165,7 +167,16 @@ public class DecoratorSkin extends SkinBase<Decorator> {
Node node = createNavBar(skinnable, s.isTitleBarTransparent(), s.getLeftPaneWidth(), s.isBackable(), skinnable.canCloseProperty().get(), skinnable.showCloseAsHomeProperty().get(), s.isRefreshable(), s.getTitle(), s.getTitleNode()); 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; double targetOpacity = s.isTitleBarTransparent() ? 0 : 1;
if (s.isAnimate()) { 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 { } else {
navBarPane.getChildren().setAll(node); navBarPane.getChildren().setAll(node);
} }

View File

@ -26,6 +26,7 @@ import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.construct.Navigator; import org.jackhuang.hmcl.ui.construct.Navigator;
import org.jackhuang.hmcl.ui.construct.TabControl; import org.jackhuang.hmcl.ui.construct.TabControl;
import org.jackhuang.hmcl.ui.construct.TabHeader; import org.jackhuang.hmcl.ui.construct.TabHeader;
import org.jackhuang.hmcl.ui.wizard.Navigation;
public abstract class DecoratorTabPage extends DecoratorTransitionPage implements TabControl { public abstract class DecoratorTabPage extends DecoratorTransitionPage implements TabControl {
@ -36,10 +37,10 @@ public abstract class DecoratorTabPage extends DecoratorTransitionPage implement
} }
if (newValue.getNode() != null) { if (newValue.getNode() != null) {
onNavigating(getCurrentPage()); 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()); navigate(newValue.getNode(), ContainerAnimations.FADE.getAnimationProducer());
onNavigated(getCurrentPage()); 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));
} }
}); });
} }