JavaFX Marquee动画 [英] JavaFX Marquee Animation
问题描述
您可能已经看过一些应用程序,当标签中的 String
无法完全显示时,它会被设置为动画并且会返回和返回,以便用户可以看到选项卡包含的字符串。当您的手机显示不足以显示整个标签时,Android正在进行设置。
You maybe have seen some apps that when the String
in a tab can't be fully shown then it is animated and is going back and front so the user can see what String the tab contains.Android is doing that is settings when your phone display is not enough to show the the whole label.
以下是在 JavaFX
使用服务
,但这不是一个好方法。
Below is a code to achieve it in JavaFX
using Service
,but it is not a good way.
问题是:
以下是我如何使用动画或JavaFX类中的其他构建来实现的?
The Question is: Here is how i can do it using Animation or another build in JavaFX class?
代码:
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import tools.InfoTool;
public class MoveTitleService extends Service<Void>{
private String title;
volatile boolean doAnimation;
private int counter;
public Label movingText = new Label("A reallyyy big teeeeexxxxxxxxxxxxxxxxxxxxxxxt");
/**
*Constructor
*/
public MoveTitleService() {
movingText.setFont(Font.font("null",FontWeight.BOLD,14));
movingText.setTextFill(Color.WHITE);
setOnSucceeded( s ->{
movingText.setText("");
});
}
//Start the Service
public void startTheService(String title) {
this.title = title;
doAnimation = true;
restart();
}
//Stop the Service
public void stopService(){
doAnimation=false;
}
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
while (doAnimation) {
//System.out.println("MoveTitleService is Running...");
// One letter at a time
for (int m = 0; m <= title.length(); m++) {
counter=m;
Platform.runLater( () ->{
movingText.setText(title.substring(0, counter) + addSpaces(title.length() - counter));
});
if(!doAnimation) break;
Thread.sleep(150);
}
// Disappearing to back
for (int m = 0; m < title.length(); m++) {
counter=m;
Platform.runLater( () ->{
movingText.setText(title.substring(counter));
});
if(!doAnimation) break;
Thread.sleep(150);
}
// Appearing to front
for (int m = 1; m <= title.length(); m++) {
counter=m;
Platform.runLater( () ->{
movingText.setText(title.substring(title.length() - counter));
});
if(!doAnimation) break;
Thread.sleep(150);
}
if(!doAnimation) break;
for(int i=0; i<3000/150; i++)
Thread.sleep(150);
Thread.sleep(3000);
}
return null;
}
private String addSpaces(int spaces) {
String z = "";
for (int i = 0; i <= spaces; i++)
z += " ";
return z;
}
};
}
}
推荐答案
您可以使用时间轴
:
// min distance to Pane bounds
private static final double OFFSET = 25;
@Override
public void start(Stage primaryStage) {
Text text = new Text("A reallyyy big teeeeexxxxxxxxxxxxxxxxxxxxxxxt!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
text.setLayoutY(25);
text.setManaged(false);
text.setLayoutX(OFFSET);
Pane pane = new Pane(text);
pane.setMinHeight(50);
Timeline timeline = new Timeline();
KeyFrame updateFrame = new KeyFrame(Duration.seconds(1 / 60d), new EventHandler<ActionEvent>() {
private boolean rightMovement;
@Override
public void handle(ActionEvent event) {
double tW = text.getLayoutBounds().getWidth();
double pW = pane.getWidth();
double layoutX = text.getLayoutX();
if (2 * OFFSET + tW <= pW && layoutX >= OFFSET) {
// stop, if the pane is large enough and the position is correct
text.setLayoutX(OFFSET);
timeline.stop();
} else {
if ((rightMovement && layoutX >= OFFSET) || (!rightMovement && layoutX + tW + OFFSET <= pW)) {
// invert movement, if bounds are reached
rightMovement = !rightMovement;
}
// update position
if (rightMovement) {
layoutX += 1;
} else {
layoutX -= 1;
}
text.setLayoutX(layoutX);
}
}
});
timeline.getKeyFrames().add(updateFrame);
timeline.setCycleCount(Animation.INDEFINITE);
// listen to bound changes of the elements to start/stop the animation
InvalidationListener listener = o -> {
double textWidth = text.getLayoutBounds().getWidth();
double paneWidth = pane.getWidth();
if (textWidth + 2 * OFFSET > paneWidth
&& timeline.getStatus() != Animation.Status.RUNNING) {
timeline.play();
}
};
text.layoutBoundsProperty().addListener(listener);
pane.widthProperty().addListener(listener);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
请注意,需要自行重复更新头寸,因为<$ c运行时无法调整$ c>动画,因此在动画期间任何调整大小都需要重复更新...
Note that repeadedly updating the position yourself needs to be done, since Animation
s cannot be adjusted while running, so for any resizing to take effect during the animation, you need repeated updates...
这篇关于JavaFX Marquee动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!