在開發視窗軟體時幾乎都會遇到一個問題:放大縮小跑版
要因應各種不同的解析度/螢幕比例,最好的方式就是根據不同螢幕去做最佳化,但是這是一種幾乎做不完的工程,於是我在開發程式時的思路就是將UI都比照影片的方式辦理,進行全畫面的等比放大/縮小,既能節省開發時間,也能減少跑版問題。
1.Fxml檔的root元件依照以下方式排列與設定屬性:
root使用GridPane,並且裡面放一個AnchorPane比較好設計畫面。

GridPane依照以下屬性設定:

然後AnchorPane也設定成以下屬性:

說明:
1.GridPane的背景顏色為APP的底色
2.GridPane跟AnchorPane的Pref Widtth跟Pref Height
需要一個基本解析度做開發,如果螢幕小於這個解析度,還是會遇到顯示問題(畫面超出螢幕範圍),所以這邊須配合軟體系統需求做規劃。
這兩個元件的解析度需要設成一樣,才能同步縮放。
2.程式碼加入相對應處理:
由程式碼去監控畫面尺寸變化,並做比例縮放的動作
private MainActivityController mMainActivityController;
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("fxml/activity_main.fxml"));
Pane root = fxmlLoader.load();
stage.setTitle("World");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setMinWidth(800);
stage.setMinHeight(600);
stage.show();
mMainActivityController = fxmlLoader.getController();
//畫面縮放功能
letterbox(scene, root);
}
private void letterbox(final Scene scene, final Pane contentPane) {
final double initWidth = scene.getWidth();
final double initHeight = scene.getHeight();
final double ratio = initWidth / initHeight;
SceneSizeChangeListener sizeListener = new SceneSizeChangeListener(scene, ratio, initHeight, initWidth, contentPane);
scene.widthProperty().addListener(sizeListener);
scene.heightProperty().addListener(sizeListener);
}
private record SceneSizeChangeListener(Scene scene, double ratio, double initHeight, double initWidth,
Pane contentPane) implements ChangeListener<Number> {
@Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
final double newWidth = scene.getWidth();
final double newHeight = scene.getHeight();
double scaleFactor =
newWidth / newHeight > ratio
? newHeight / initHeight
: newWidth / initWidth;
//如須能縮小,則設為0(或一個最小的倍數)
if (scaleFactor >= 1) {
Scale scale = new Scale(scaleFactor, scaleFactor);
//如需要中心放大,則使用(newWidth/2),(newHeight/2),測試用的root元件為GridPane,Alignment設為TOP_LEFT,第二層為AnchorPane,V/Halignment設為CENTER
scale.setPivotX(newWidth / 2);
scale.setPivotY(newHeight / 2);
scene.getRoot().getTransforms().setAll(scale);
contentPane.setPrefWidth(newWidth / scaleFactor);
contentPane.setPrefHeight(newHeight / scaleFactor);
} else {
contentPane.setPrefWidth(Math.max(initWidth, newWidth));
contentPane.setPrefHeight(Math.max(initHeight, newHeight));
}
}
}
這樣就能自由等比放大~全螢幕了
-END-
發佈留言