如何用JavaFX实现Windows 10风格导航抽屉及主内容伸缩?
Absolutely! You can absolutely replicate that Windows 10-style navigation drawer behavior—where icons show by default, and text appears only when you click the hamburger button, with the main content area resizing accordingly—using either core JavaFX components or third-party libraries. Let me walk you through both approaches:
Core JavaFX Implementation
If you prefer to build it from scratch without external dependencies, you can combine JavaFX's layout containers and animation APIs to get the desired effect. Here's a step-by-step breakdown:
- Layout Structure: Use a
BorderPaneas your root container. The left region will hold your navigation drawer (aVBox), and the center region will contain your main content. - Drawer Items: Each navigation item should be an
HBoxcontaining anImageView(for the icon) and aLabel(for the text). By default, hide theLabelso only icons are visible. - Animation & Toggle Logic: Use a
Timelineto animate the drawer's width when the hamburger button is clicked. Toggle the visibility of the text labels alongside the width animation. - Auto-Resizing Main Content: Since the main content is in the
BorderPane's center, it will automatically resize as the left drawer expands or contracts—no extra work needed here!
Example Code Snippet
import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Duration; import java.util.ArrayList; import java.util.List; public class Windows10DrawerDemo extends Application { private boolean drawerExpanded = false; private final List<HBox> drawerItems = new ArrayList<>(); private final VBox drawerPane = new VBox(10); @Override public void start(Stage stage) { // Setup hamburger button Button hamburgerButton = new Button("☰"); hamburgerButton.setOnAction(e -> toggleDrawer()); // Create drawer items createDrawerItem("Home", "home-icon.png"); createDrawerItem("Settings", "settings-icon.png"); createDrawerItem("Documents", "docs-icon.png"); drawerPane.setPadding(new Insets(10)); drawerPane.setPrefWidth(60); // Default width for icons only // Main content area Label mainContent = new Label("Main Content Area"); mainContent.setStyle("-fx-font-size: 24px; -fx-padding: 20px;"); // Root layout BorderPane root = new BorderPane(); root.setTop(hamburgerButton); root.setLeft(drawerPane); root.setCenter(mainContent); Scene scene = new Scene(root, 800, 600); stage.setTitle("Windows 10 Style Drawer"); stage.setScene(scene); stage.show(); } private void createDrawerItem(String text, String iconPath) { ImageView icon = new ImageView(new Image(iconPath)); icon.setFitWidth(32); icon.setFitHeight(32); Label label = new Label(text); label.setVisible(false); // Hide text by default HBox item = new HBox(10, icon, label); item.setPadding(new Insets(5)); drawerItems.add(item); drawerPane.getChildren().add(item); } private void toggleDrawer() { Timeline timeline = new Timeline(); double targetWidth = drawerExpanded ? 60 : 200; // Animate drawer width KeyValue widthKV = new KeyValue(drawerPane.prefWidthProperty(), targetWidth); KeyFrame widthKF = new KeyFrame(Duration.millis(300), widthKV); timeline.getKeyFrames().add(widthKF); // Toggle text visibility drawerItems.forEach(item -> { Label label = (Label) item.getChildren().get(1); label.setVisible(!drawerExpanded); }); drawerExpanded = !drawerExpanded; timeline.play(); } public static void main(String[] args) { launch(args); } }
Third-Party Library Options
If you want a more polished, out-of-the-box solution, these libraries have built-in components that match your requirement:
ControlsFX
The NavigationDrawer component in ControlsFX is designed exactly for this use case. It automatically shows only icons when collapsed, and expands to show text when opened. It also handles the main content resizing automatically.
Quick Usage Example:
import org.controlsfx.control.DrawerPane; import org.controlsfx.control.NavigationDrawer; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class ControlsFXDrawerDemo extends Application { @Override public void start(Stage stage) { DrawerPane drawerPane = new DrawerPane(); NavigationDrawer navDrawer = new NavigationDrawer(); // Add navigation items with icon and text NavigationDrawer.Item homeItem = new NavigationDrawer.Item("Home", new ImageView(new Image("home-icon.png"))); NavigationDrawer.Item settingsItem = new NavigationDrawer.Item("Settings", new ImageView(new Image("settings-icon.png"))); navDrawer.getItems().addAll(homeItem, settingsItem); drawerPane.setSideDrawer(navDrawer); // Hamburger button to toggle drawer Button hamburgerButton = new Button("☰"); hamburgerButton.setOnAction(e -> { if (drawerPane.isDrawerVisible()) { drawerPane.hideDrawer(); } else { drawerPane.showDrawer(); } }); BorderPane root = new BorderPane(); root.setTop(hamburgerButton); root.setCenter(drawerPane); Scene scene = new Scene(root, 800, 600); stage.setTitle("ControlsFX Drawer"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
JFoenix
JFoenix's JFXDrawer component also supports this behavior. You can customize the drawer's content to show icons only when collapsed, and add text on expansion. It includes smooth animations and integrates well with other JFoenix components.
Tips for Polish
- Adjust the animation duration (
Duration.millis(300)in the examples) to match Windows 10's feel. - Add hover effects to drawer items for better interactivity.
- Ensure icons are sized consistently (32x32 is a good standard for Windows 10-style navigation).
内容的提问来源于stack exchange,提问作者Volkeee

