如何在 JavaFX 中为文本节点的字体大小设置动画
How to animate font size of text node in JavaFX
我想知道是否有办法为节点的文本大小设置动画(例如 Label
),例如通过过渡更改文本大小?我试图为节点的 fontProperty()
设置一个 Timeline
,但实际上没有任何反应:
Label label = new Label(); // The text node
Font font = Font.font(100); // Change the text size to 100
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(label.fontProperty(), label.getFont())),
new KeyFrame(Duration.millis(1000), new KeyValue(label.fontProperty(), font))
);
我能想到的唯一方法是缩放节点的 ACTUAL 大小。但不利的是,它也会改变节点的布局(位置随其大小而变化)。此外,如果您真的希望文本大小与特定的 font-size
值一样 big/small,那么它是不准确的。
Label label = new Label(); // The text node
double size = 2; // Scale the size by 2
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO,
new KeyValue(label.scaleXProperty(), label.getScaleX()),
new KeyValue(label.scaleYProperty(), label.getScaleY())),
new KeyFrame(Duration.millis(1000),
new KeyValue(label.scaleXProperty(), size),
new KeyValue(label.scaleYProperty(), size))
);
还有其他方法可以实现吗?
更新
我在此转换中使用的公式(这是为了防止我忘记或丢失源代码,以便我可以返回此处并在此处共享)。
@Override
protected void interpolate(double frac) {
// Determine which is less/greater value between the initial and
// ending value, then get their difference. This is to resolve the
// end value when we either increase or decrease the initial value.
double min = Math.min(start, end); // returns the smaller value
double max = Math.max(start, end); // returns the higher value
double diff = max - min; // the positive difference between the two value.
// Since our start will always be the initial value regardless if
// it is greater or less than the end, we will simply increase or
// decrease its value until it reaches the desired end value.
// Also, computing the difference between their value was to determine
// if they both have equal values, it means (max - min) is always 0
// as well as multiplying it to frac, therefore, there will be a
// 0 value to increase or decrease.
double size = (start == min) ?
start + (diff * frac) : // start is smaller so we'll just increase its value
start - (diff * frac); // decrease if it has the higher value than end
UIcontrol.setFont(Font.font(size));
}
这是一个实现自定义 Interpolator
的示例。
您可以探索 Transition
class 来自 here. Note there the properties inherited from class javafx.animation.Animation 的其他方法!
import javafx.animation.Interpolator;
import javafx.animation.Transition;
import javafx.scene.control.Labeled;
import javafx.scene.text.Font;
import javafx.util.Duration;
public class TextSizeTransition extends Transition{
private Labeled UIcontrol; // a little generic -> subclasses: ButtonBase, Cell, Label, TitledPane
private int start, end; // initial and final size of the text
public TextSizeTransition(Labeled UIcontrol, int start, int end, Duration duration) {
this.UIcontrol = UIcontrol;
this.start = start;
this.end = end - start; // minus start because of (end * frac) + start in interpolate()
setCycleDuration(duration);
setInterpolator(Interpolator.LINEAR);
//setCycleCount(100);
// and a lot of other methods
}
@Override
protected void interpolate(double frac) {
// frac value goes from 0 to 1
// when frac is zero -> size is start
// when frac is 1 -> size is end + start
//(that's why we this.end = end - start; above to back to original end value)
int size = (int) ((end * frac) + start);
if(size<=end) {
UIcontrol.setFont(Font.font(size));
}else { // once the size reaches the destination (i.e. end value)
// back to the start size if you want
//UIcontrol.setFont(Font.font(start));
}
}
}
例子
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TextAnimation extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
Label label = new Label("Text Size Animation");
Pane root = new Pane(label);
root.setPrefSize(1100, 300);
Scene scene = new Scene(root);
// transit text size from 10 to 100 during 5 seconds
TextSizeTransition trans = new TextSizeTransition(label, 10, 100,Duration.millis(5000));
stage.setScene(scene);
stage.show();
trans.play();
}
}
结果
我想知道是否有办法为节点的文本大小设置动画(例如 Label
),例如通过过渡更改文本大小?我试图为节点的 fontProperty()
设置一个 Timeline
,但实际上没有任何反应:
Label label = new Label(); // The text node
Font font = Font.font(100); // Change the text size to 100
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(label.fontProperty(), label.getFont())),
new KeyFrame(Duration.millis(1000), new KeyValue(label.fontProperty(), font))
);
我能想到的唯一方法是缩放节点的 ACTUAL 大小。但不利的是,它也会改变节点的布局(位置随其大小而变化)。此外,如果您真的希望文本大小与特定的 font-size
值一样 big/small,那么它是不准确的。
Label label = new Label(); // The text node
double size = 2; // Scale the size by 2
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO,
new KeyValue(label.scaleXProperty(), label.getScaleX()),
new KeyValue(label.scaleYProperty(), label.getScaleY())),
new KeyFrame(Duration.millis(1000),
new KeyValue(label.scaleXProperty(), size),
new KeyValue(label.scaleYProperty(), size))
);
还有其他方法可以实现吗?
更新
我在此转换中使用的公式(这是为了防止我忘记或丢失源代码,以便我可以返回此处并在此处共享)。
@Override
protected void interpolate(double frac) {
// Determine which is less/greater value between the initial and
// ending value, then get their difference. This is to resolve the
// end value when we either increase or decrease the initial value.
double min = Math.min(start, end); // returns the smaller value
double max = Math.max(start, end); // returns the higher value
double diff = max - min; // the positive difference between the two value.
// Since our start will always be the initial value regardless if
// it is greater or less than the end, we will simply increase or
// decrease its value until it reaches the desired end value.
// Also, computing the difference between their value was to determine
// if they both have equal values, it means (max - min) is always 0
// as well as multiplying it to frac, therefore, there will be a
// 0 value to increase or decrease.
double size = (start == min) ?
start + (diff * frac) : // start is smaller so we'll just increase its value
start - (diff * frac); // decrease if it has the higher value than end
UIcontrol.setFont(Font.font(size));
}
这是一个实现自定义 Interpolator
的示例。
您可以探索 Transition
class 来自 here. Note there the properties inherited from class javafx.animation.Animation 的其他方法!
import javafx.animation.Interpolator;
import javafx.animation.Transition;
import javafx.scene.control.Labeled;
import javafx.scene.text.Font;
import javafx.util.Duration;
public class TextSizeTransition extends Transition{
private Labeled UIcontrol; // a little generic -> subclasses: ButtonBase, Cell, Label, TitledPane
private int start, end; // initial and final size of the text
public TextSizeTransition(Labeled UIcontrol, int start, int end, Duration duration) {
this.UIcontrol = UIcontrol;
this.start = start;
this.end = end - start; // minus start because of (end * frac) + start in interpolate()
setCycleDuration(duration);
setInterpolator(Interpolator.LINEAR);
//setCycleCount(100);
// and a lot of other methods
}
@Override
protected void interpolate(double frac) {
// frac value goes from 0 to 1
// when frac is zero -> size is start
// when frac is 1 -> size is end + start
//(that's why we this.end = end - start; above to back to original end value)
int size = (int) ((end * frac) + start);
if(size<=end) {
UIcontrol.setFont(Font.font(size));
}else { // once the size reaches the destination (i.e. end value)
// back to the start size if you want
//UIcontrol.setFont(Font.font(start));
}
}
}
例子
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TextAnimation extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
Label label = new Label("Text Size Animation");
Pane root = new Pane(label);
root.setPrefSize(1100, 300);
Scene scene = new Scene(root);
// transit text size from 10 to 100 during 5 seconds
TextSizeTransition trans = new TextSizeTransition(label, 10, 100,Duration.millis(5000));
stage.setScene(scene);
stage.show();
trans.play();
}
}
结果