在播放 UI 动画前应用 UI 布局 (#7076)
This commit is contained in:
1 parent
fb8a96a170
commit
58eb452e90
4 files changed
+28
-50
No files matched your search
@@ -168,14 +168,6 @@ public final class Controllers {
|
||||
return gameInstancePage;
|
||||
}
|
||||
|
||||
@FXThread
|
||||
public static void prepareGameInstancePage() {
|
||||
if (gameInstancePage == null) {
|
||||
LOG.info("Prepare the game instance page");
|
||||
gameInstancePage = FXUtils.prepareNode(new GameInstancePage());
|
||||
}
|
||||
}
|
||||
|
||||
@FXThread
|
||||
public static GameListPage getGameListPage() {
|
||||
return gameListPage.get();
|
||||
@@ -194,14 +186,6 @@ public final class Controllers {
|
||||
return settingsPage;
|
||||
}
|
||||
|
||||
@FXThread
|
||||
public static void prepareSettingsPage() {
|
||||
if (settingsPage == null) {
|
||||
LOG.info("Prepare the settings page");
|
||||
settingsPage = FXUtils.prepareNode(new LauncherSettingsPage());
|
||||
}
|
||||
}
|
||||
|
||||
@FXThread
|
||||
public static AccountListPage getAccountListPage() {
|
||||
return accountListPage.get();
|
||||
@@ -215,14 +199,6 @@ public final class Controllers {
|
||||
return downloadPage;
|
||||
}
|
||||
|
||||
@FXThread
|
||||
public static void prepareDownloadPage() {
|
||||
if (downloadPage == null) {
|
||||
LOG.info("Prepare the download page");
|
||||
downloadPage = FXUtils.prepareNode(new DownloadPage());
|
||||
}
|
||||
}
|
||||
|
||||
@FXThread
|
||||
public static Node getTerracottaPage() {
|
||||
return terracottaPage.get();
|
||||
|
||||
@@ -36,7 +36,6 @@ import javafx.collections.ObservableList;
|
||||
import javafx.collections.ObservableMap;
|
||||
import javafx.event.Event;
|
||||
import javafx.event.EventDispatcher;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.event.EventType;
|
||||
import javafx.geometry.Bounds;
|
||||
import javafx.geometry.Rectangle2D;
|
||||
@@ -1226,16 +1225,6 @@ public final class FXUtils {
|
||||
return node;
|
||||
}
|
||||
|
||||
public static void prepareOnMouseEnter(Node node, Runnable action) {
|
||||
node.addEventFilter(MouseEvent.MOUSE_ENTERED, new EventHandler<>() {
|
||||
@Override
|
||||
public void handle(MouseEvent e) {
|
||||
node.removeEventFilter(MouseEvent.MOUSE_ENTERED, this);
|
||||
action.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> void onScroll(Node node, List<T> list,
|
||||
ToIntFunction<List<T>> finder,
|
||||
Consumer<T> updater
|
||||
|
||||
@@ -26,31 +26,46 @@ import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.util.Duration;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jetbrains.annotations.NotNullByDefault;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/// Displays one page, retaining the preceding page while a transition runs.
|
||||
/// Content changes must be made on the JavaFX Application Thread.
|
||||
@NotNullByDefault
|
||||
public class TransitionPane extends StackPane {
|
||||
|
||||
private Node currentNode;
|
||||
/// The requested page, or `null` before content is assigned.
|
||||
private @Nullable Node currentNode;
|
||||
|
||||
/// Creates an empty container that clips content to its bounds.
|
||||
public TransitionPane() {
|
||||
FXUtils.setOverflowHidden(this);
|
||||
}
|
||||
|
||||
public Node getCurrentNode() {
|
||||
/// Returns the requested page, or `null` if none has been assigned.
|
||||
public @Nullable Node getCurrentNode() {
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
/// Replaces the content using [Motion#SHORT4] and [Motion#EASE].
|
||||
public final void setContent(Node newView, AnimationProducer transition) {
|
||||
setContent(newView, transition, Motion.SHORT4);
|
||||
}
|
||||
|
||||
/// Replaces the content using the given duration and [Motion#EASE].
|
||||
public final void setContent(Node newView, AnimationProducer transition, Duration duration) {
|
||||
setContent(newView, transition, duration, Motion.EASE);
|
||||
}
|
||||
|
||||
/// Replaces the content using the given animation and timing.
|
||||
/// The first page, repeated assignments of the current page, and replacements
|
||||
/// without animations are displayed immediately. Otherwise, CSS and layout
|
||||
/// are processed in this container before the animation starts in a later
|
||||
/// event-loop task. Mouse input is disabled while the transition is pending
|
||||
/// or running.
|
||||
public void setContent(Node newView, AnimationProducer transition,
|
||||
Duration duration, Interpolator interpolator) {
|
||||
Node previousNode = currentNode != newView && getWidth() > 0 && getHeight() > 0 ? currentNode : null;
|
||||
@Nullable Node previousNode = currentNode != newView && getWidth() > 0 && getHeight() > 0 ? currentNode : null;
|
||||
currentNode = newView;
|
||||
|
||||
if (!AnimationUtils.isAnimationEnabled() || previousNode == null || transition == ContainerAnimations.NONE) {
|
||||
@@ -64,7 +79,7 @@ public class TransitionPane extends StackPane {
|
||||
setMouseTransparent(true);
|
||||
transition.init(this, previousNode, newView);
|
||||
|
||||
CacheHint cacheHint = newView instanceof Cacheable cacheable
|
||||
@Nullable CacheHint cacheHint = newView instanceof Cacheable cacheable
|
||||
? cacheable.getCacheHint(transition)
|
||||
: null;
|
||||
|
||||
@@ -73,8 +88,12 @@ public class TransitionPane extends StackPane {
|
||||
newView.setCacheHint(cacheHint);
|
||||
}
|
||||
|
||||
// runLater or "init" will not work
|
||||
// Let navigation handlers finish updating the page before preparing it.
|
||||
Platform.runLater(() -> {
|
||||
// runLater alone does not guarantee a CSS or layout pass. Keep that
|
||||
// first-use work outside the animation's elapsed time.
|
||||
applyCss();
|
||||
layout();
|
||||
Animation newAnimation = transition.animate(
|
||||
this,
|
||||
previousNode,
|
||||
@@ -95,15 +114,19 @@ public class TransitionPane extends StackPane {
|
||||
|
||||
}
|
||||
|
||||
/// Prepares page properties and creates animations for content replacements.
|
||||
public interface AnimationProducer {
|
||||
/// Resets page transforms, making the old page opaque and the new page transparent.
|
||||
default void init(TransitionPane container, Node previousNode, Node nextNode) {
|
||||
AnimationUtils.reset(previousNode, true);
|
||||
AnimationUtils.reset(nextNode, false);
|
||||
}
|
||||
|
||||
/// Creates the transition between the prepared pages using the given timing.
|
||||
Animation animate(Pane container, Node previousNode, Node nextNode,
|
||||
Duration duration, Interpolator interpolator);
|
||||
|
||||
/// Returns the reverse transition, or `null` if none is specified.
|
||||
default @Nullable TransitionPane.AnimationProducer opposite() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.ui.account.AccountAdvancedListItem;
|
||||
import org.jackhuang.hmcl.ui.account.AccountListPopupMenu;
|
||||
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
|
||||
import org.jackhuang.hmcl.ui.construct.AdvancedListBox;
|
||||
import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
||||
@@ -131,9 +130,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
@Nullable GameInstanceID currentId = currentGame != null ? currentGame.getId() : null;
|
||||
return Lang.indexWhere(list, instance -> instance.getId().equals(currentId));
|
||||
}, instance -> instance.getRepository().setSelectedInstance(instance));
|
||||
if (AnimationUtils.isAnimationEnabled()) {
|
||||
FXUtils.prepareOnMouseEnter(gameListItem, Controllers::prepareGameInstancePage);
|
||||
}
|
||||
FXUtils.onSecondaryButtonClicked(gameListItem, () -> showGameListPopupMenu(gameListItem));
|
||||
|
||||
// third item in left sidebar
|
||||
@@ -148,9 +144,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
downloadItem.setLeftIcon(SVG.DOWNLOAD);
|
||||
downloadItem.setTitle(i18n("download"));
|
||||
downloadItem.setOnAction(e -> Controllers.navigate(Controllers.getDownloadPage()));
|
||||
if (AnimationUtils.isAnimationEnabled()) {
|
||||
FXUtils.prepareOnMouseEnter(downloadItem, Controllers::prepareDownloadPage);
|
||||
}
|
||||
|
||||
// fifth item in left sidebar
|
||||
AdvancedListItem launcherSettingsItem = new AdvancedListItem();
|
||||
@@ -160,9 +153,6 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
|
||||
Controllers.getSettingsPage().showGameSettings(GameDirectoryManager.getSelectedRepository());
|
||||
Controllers.navigate(Controllers.getSettingsPage());
|
||||
});
|
||||
if (AnimationUtils.isAnimationEnabled()) {
|
||||
FXUtils.prepareOnMouseEnter(launcherSettingsItem, Controllers::prepareSettingsPage);
|
||||
}
|
||||
|
||||
// sixth item in left sidebar
|
||||
AdvancedListItem terracottaItem = new AdvancedListItem();
|
||||
|
||||
Reference in new issue
Block a user