JavaFX 过渡

2018-03-18 18:55 更新

JavaFX教程 - JavaFX过渡


JavaFX中的动画可以分为时间轴动画和过渡。

时间轴和过渡是javafx.animation.Animation类的子类。

JavaFX中的过渡提供了将动画合并到内部时间轴中的方法。JavaFX有内置的过渡动画,这是方便的类来执行常见的动画效果。这里是一些最常见的动画过渡类

  • javafx.animation.FadeTransition
  • javafx.animation.PathTransition
  • javafx.animation.ScaleTransition
  • javafx.animation.TranslateTransition

FadeTransition中定义的淡入淡出过渡目标是节点的不透明属性,用于淡入淡出的动画效果。

PathTransition中定义的路径过渡使节点能够跟随生成的路径。

ScaleTransition中定义的缩放过渡定位节点的scaleX,scaleY和scaleZ属性以调整节点大小。

TranslateTransition中定义的翻译过渡定位了节点的translateX,translateY和translateZ属性,以便在屏幕上移动节点。

褪色过渡

import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

  public static void main(String[] args) {
    Application.launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    Group group = new Group();

    Rectangle rect = new Rectangle(20,20,200,200);
    
    FadeTransition ft = new FadeTransition(Duration.millis(5000), rect);
    ft.setFromValue(1.0);
    ft.setToValue(0.0);
    ft.play();
    
    group.getChildren().add(rect);
    
    Scene scene = new Scene(group, 300, 200);
    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

上面的代码生成以下结果。

null

填充过渡

import javafx.animation.FillTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.DropShadow;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {
  public static void main(String[] args) {
    Application.launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    primaryStage.setTitle("");
    Group root = new Group();
    Scene scene = new Scene(root, 300, 250, Color.WHITE);

    Group g = new Group();

    DropShadow ds = new DropShadow();
    ds.setOffsetY(3.0);
    ds.setColor(Color.color(0.4, 0.4, 0.4));

    Ellipse ellipse = new Ellipse();
    ellipse.setCenterX(50.0f);
    ellipse.setCenterY(50.0f);
    ellipse.setRadiusX(50.0f);
    ellipse.setRadiusY(25.0f);
    ellipse.setEffect(ds);

    FillTransition ft = new FillTransition(Duration.millis(3000), ellipse, Color.RED, Color.BLUE);
    ft.setAutoReverse(true);
    ft.play();
    
    g.getChildren().add(ellipse);

    root.getChildren().add(g);
    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

上面的代码生成以下结果。

null

路径过渡

路径过渡在一个给定时间内沿着从一端到另一端的路径移动节点。

/*
 * Copyright (c) 2011, Pro JavaFX Authors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of JFXtras nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Metronome1Main.fx - A simple example of animation using a Timeline
 *
 *  Developed 2011 by James L. Weaver jim.weaver [at] javafxpert.com
 *  as a JavaFX SDK 2.0 example for the Pro JavaFX book.
 */
//package projavafx.metronomepathtransition.ui;

import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.animation.PathTransitionBuilder;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.GroupBuilder;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcToBuilder;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.EllipseBuilder;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathBuilder;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {
  Button startButton;
  Button pauseButton;
  Button resumeButton;
  Button stopButton;
  Ellipse ellipse = EllipseBuilder.create()
    .centerX(100)
    .centerY(50)
    .radiusX(4)
    .radiusY(8)
    .fill(Color.BLUE)
    .build();
  
  Path path = PathBuilder.create()
    .elements(
      new MoveTo(100, 50),
      ArcToBuilder.create()
        .x(300)
        .y(50)
        .radiusX(350)
        .radiusY(350)
        .sweepFlag(true)
        .build()
    )
    .build();
  
  PathTransition anim = PathTransitionBuilder.create()
    .duration(new Duration(1000.0))
    .node(ellipse)
    .path(path)
    .orientation(OrientationType.ORTHOGONAL_TO_TANGENT)
    .interpolator(Interpolator.LINEAR)
    .autoReverse(true)
    .cycleCount(Timeline.INDEFINITE)
    .build();
  
  public static void main(String[] args) {
    Application.launch(args);
  }
  
  @Override
  public void start(Stage stage) {
    Scene scene  = SceneBuilder.create()
      .width(400)
      .height(500)
      .root(
        GroupBuilder.create()
          .children(
            ellipse,
            HBoxBuilder.create()
              .layoutX(60)
              .layoutY(420)
              .spacing(10)
              .children(
                startButton = ButtonBuilder.create()
                  .text("Start")
                  .onAction(new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent e) {
                      anim.playFromStart();
                    }
                  })
                  .build(),
                pauseButton = ButtonBuilder.create()
                  .text("Pause")
                  .onAction(new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent e) {
                      anim.pause();
                    }
                  })
                  .build(),
                resumeButton = ButtonBuilder.create()
                  .text("Resume")
                  .onAction(new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent e) {
                      anim.play();
                    }
                  })
                  .build(),
                stopButton = ButtonBuilder.create()
                  .text("Stop")
                  .onAction(new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent e) {
                      anim.stop();
                    }
                  })
                  .build()
              )
              .build()
          )
          .build()
      )
      .build();

    startButton.disableProperty().bind(anim.statusProperty()
            .isNotEqualTo(Animation.Status.STOPPED));
    pauseButton.disableProperty().bind(anim.statusProperty()
            .isNotEqualTo(Animation.Status.RUNNING));
    resumeButton.disableProperty().bind(anim.statusProperty()
            .isNotEqualTo(Animation.Status.PAUSED));
    stopButton.disableProperty().bind(anim.statusProperty()
            .isEqualTo(Animation.Status.STOPPED));
    
    stage.setScene(scene);
    stage.setTitle("Metronome using PathTransition");
    stage.show();
  }
}

上面的代码生成以下结果。

null

沿着路径的动画

import javafx.animation.PathTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

  @Override
  public void start(final Stage stage) throws Exception {
    final Group group = new Group();
    final Scene scene = new Scene(group, 600, 400, Color.GHOSTWHITE);
    stage.setScene(scene);
    stage.setTitle("JavaFX 2 Animations");
    stage.show();
    final Circle circle = new Circle(20, 20, 15);
    circle.setFill(Color.DARKRED);

    final Path path = new Path();
    path.getElements().add(new MoveTo(20, 20));
    path.getElements().add(new CubicCurveTo(30, 10, 380, 120, 200, 120));
    path.getElements().add(new CubicCurveTo(200, 1120, 110, 240, 380, 240));
    path.setOpacity(0.5);

    group.getChildren().add(path);
    group.getChildren().add(circle);
    final PathTransition pathTransition = new PathTransition();

    pathTransition.setDuration(Duration.seconds(8.0));
    pathTransition.setDelay(Duration.seconds(.5));
    pathTransition.setPath(path);
    pathTransition.setNode(circle);
    pathTransition
        .setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
    pathTransition.setCycleCount(Timeline.INDEFINITE);
    pathTransition.setAutoReverse(true);
    pathTransition.play();
  }

  public static void main(final String[] arguments) {
    Application.launch(arguments);
  }
}

上面的代码生成以下结果。

null

并行过渡

并行过渡同时执行多个过渡。

/*
 * Copyright (c) 2011, Pro JavaFX Authors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of JFXtras nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Metronome1Main.fx - A simple example of animation using a Timeline
 *
 *  Developed 2011 by James L. Weaver jim.weaver [at] javafxpert.com
 *  as a JavaFX SDK 2.0 example for the Pro JavaFX book.
 */
import javafx.animation.FadeTransition;
import javafx.animation.ParallelTransition;
import javafx.animation.RotateTransition;
import javafx.animation.ScaleTransition;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

  public static void main(String[] args) {
    Application.launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    Group group = new Group();

    Rectangle rectParallel = new Rectangle(20, 20, 200, 200);

    FadeTransition fadeTransition = new FadeTransition(Duration.millis(3000),
        rectParallel);
    fadeTransition.setFromValue(1.0f);
    fadeTransition.setToValue(0.3f);
    fadeTransition.setCycleCount(2);
    fadeTransition.setAutoReverse(true);
    TranslateTransition translateTransition = new TranslateTransition(
        Duration.millis(2000), rectParallel);
    translateTransition.setFromX(50);
    translateTransition.setToX(350);
    translateTransition.setCycleCount(2);
    translateTransition.setAutoReverse(true);
    RotateTransition rotateTransition = new RotateTransition(
        Duration.millis(3000), rectParallel);
    rotateTransition.setByAngle(180f);
    rotateTransition.setCycleCount(4);
    rotateTransition.setAutoReverse(true);
    ScaleTransition scaleTransition = new ScaleTransition(
        Duration.millis(2000), rectParallel);
    scaleTransition.setToX(2f);
    scaleTransition.setToY(2f);
    scaleTransition.setCycleCount(2);
    scaleTransition.setAutoReverse(true);

    ParallelTransition parallelTransition = new ParallelTransition();
    parallelTransition.getChildren().addAll(fadeTransition,
        translateTransition, rotateTransition, scaleTransition);
    parallelTransition.setCycleCount(Timeline.INDEFINITE);
    parallelTransition.play();

    group.getChildren().add(rectParallel);

    Scene scene = new Scene(group, 300, 200);
    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

上面的代码生成以下结果。

null

顺序过渡

顺序过渡一个接一个地执行多个过渡。

/*
 * Copyright (c) 2011, Pro JavaFX Authors
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of JFXtras nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Metronome1Main.fx - A simple example of animation using a Timeline
 *
 *  Developed 2011 by James L. Weaver jim.weaver [at] javafxpert.com
 *  as a JavaFX SDK 2.0 example for the Pro JavaFX book.
 */
import javafx.animation.FadeTransition;
import javafx.animation.RotateTransition;
import javafx.animation.ScaleTransition;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

  public static void main(String[] args) {
    Application.launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    Group group = new Group();

    Rectangle rectSeq = new Rectangle(20, 20, 200, 200);

    FadeTransition fadeTransition = new FadeTransition(Duration.millis(1000),
        rectSeq);
    fadeTransition.setFromValue(1.0f);
    fadeTransition.setToValue(0.3f);
    fadeTransition.setCycleCount(1);
    fadeTransition.setAutoReverse(true);

    TranslateTransition translateTransition = new TranslateTransition(
        Duration.millis(2000), rectSeq);
    translateTransition.setFromX(50);
    translateTransition.setToX(375);
    translateTransition.setCycleCount(1);
    translateTransition.setAutoReverse(true);

    RotateTransition rotateTransition = new RotateTransition(
        Duration.millis(2000), rectSeq);
    rotateTransition.setByAngle(180f);
    rotateTransition.setCycleCount(4);
    rotateTransition.setAutoReverse(true);

    ScaleTransition scaleTransition = new ScaleTransition(
        Duration.millis(2000), rectSeq);
    scaleTransition.setFromX(1);
    scaleTransition.setFromY(1);
    scaleTransition.setToX(2);
    scaleTransition.setToY(2);
    scaleTransition.setCycleCount(1);
    scaleTransition.setAutoReverse(true);

    SequentialTransition sequentialTransition = new SequentialTransition();
    sequentialTransition.getChildren().addAll(fadeTransition,
        translateTransition, rotateTransition, scaleTransition);
    sequentialTransition.setCycleCount(Timeline.INDEFINITE);
    sequentialTransition.setAutoReverse(true);

    sequentialTransition.play();

    group.getChildren().add(rectSeq);

    Scene scene = new Scene(group, 300, 200);
    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

上面的代码生成以下结果。

null

暂停过渡

import javafx.animation.FadeTransition;
import javafx.animation.PauseTransition;
import javafx.animation.RotateTransition;
import javafx.animation.ScaleTransition;
import javafx.animation.SequentialTransition;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

  @Override
  public void start(Stage stage) {
    Group root = new Group();
    Scene scene = new Scene(root, 600, 400);
    stage.setScene(scene);
    stage.setTitle("");

    Rectangle rect = new Rectangle(100, 40, 100, 100);
    rect.setArcHeight(50);
    rect.setArcWidth(50);
    rect.setFill(Color.VIOLET);


    PauseTransition pt = new PauseTransition(Duration.millis(1000));
    FadeTransition ft = new FadeTransition(Duration.millis(2000));
    ft.setFromValue(1.0f);
    ft.setToValue(0.3f);
    ft.setAutoReverse(true);
    TranslateTransition tt = new TranslateTransition(Duration.millis(2000));
    tt.setFromX(-100f);
    tt.setToX(100f);
    tt.setAutoReverse(true);
    RotateTransition rt = new RotateTransition(Duration.millis(2000));
    rt.setByAngle(180f);
    rt.setAutoReverse(true);
    ScaleTransition st = new ScaleTransition(Duration.millis(2000));
    st.setByX(1.5f);
    st.setByY(1.5f);
    st.setAutoReverse(true);

    SequentialTransition seqT = new SequentialTransition(rect, pt, ft, tt, rt,
        st);
    seqT.play();

    root.getChildren().add(rect);

    stage.show();
  }

  public static void main(String[] args) {
    launch(args);
  }
}

上面的代码生成以下结果。

null

文本打字效果

import javafx.animation.Animation;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {
  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage stage) {
    Scene scene = new Scene(new Group());
    stage.setTitle("Sample");
    stage.setWidth(300);
    stage.setHeight(190);

    VBox vbox = new VBox();
    vbox.setLayoutX(20);
    vbox.setLayoutY(20);
    

    final String content = "Lorem ipsum";
    final Text text = new Text(10, 20, "");
    
    final Animation animation = new Transition() {
        {
            setCycleDuration(Duration.millis(2000));
        }
    
        protected void interpolate(double frac) {
            final int length = content.length();
            final int n = Math.round(length * (float) frac);
            text.setText(content.substring(0, n));
        }
    
    };
    
    animation.play();

    

    vbox.getChildren().add(text);
    vbox.setSpacing(10);
    ((Group) scene.getRoot()).getChildren().add(vbox);

    stage.setScene(scene);
    stage.show();
  }
}

上面的代码生成以下结果。

null
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号