Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.animation; 027 028import com.sun.scenario.animation.AbstractMasterTimer; 029import javafx.beans.property.ObjectProperty; 030import javafx.beans.property.SimpleObjectProperty; 031import javafx.scene.Node; 032 033/** 034 * An abstract class that contains the basic functionalities required by all 035 * {@code Transition} based animations, such as {@link PathTransition} and 036 * {@link RotateTransition}. 037 * <p> 038 * This class offers a simple framework to define animation. It provides all the 039 * basic functionality defined in {@link Animation}. {@code Transition} requires 040 * the implementation of a method {@link #interpolate(double)} which is the 041 * called in each frame, while the {@code Transition} is running. 042 * <p> 043 * In addition an extending class needs to set the duration of a single cycle 044 * with {@link Animation#setCycleDuration(javafx.util.Duration)}. This duration 045 * is usually set by the user via a duration property (as in 046 * {@link FadeTransition#duration}) for example. But it can also be calculated 047 * by the extending class as is done in {@link ParallelTransition} and 048 * {@link FadeTransition}. 049 * <p> 050 * Below is a simple example. It creates a small animation that updates the 051 * {@code text} property of a {@link javafx.scene.text.Text} node. It starts 052 * with an empty {@code String} and adds gradually letter by letter until the 053 * full {@code String} was set when the animation finishes. 054 * 055 * <pre> 056 * {@code 057 * 058 * final String content = "Lorem ipsum"; 059 * final Text text = new Text(10, 20, ""); 060 * 061 * final Animation animation = new Transition() { 062 * { 063 * setCycleDuration(Duration.millis(2000)); 064 * } 065 * 066 * protected void interpolate(double frac) { 067 * final int length = content.length(); 068 * final int n = Math.round(length * (float) frac); 069 * text.setText(content.substring(0, n)); 070 * } 071 * 072 * }; 073 * 074 * animation.play(); 075 * }</pre> 076 * 077 * @see Animation 078 * 079 */ 080public abstract class Transition extends Animation { 081 082 /** 083 * Controls the timing for acceleration and deceleration at each 084 * {@code Transition} cycle. 085 * <p> 086 * This may only be changed prior to starting the transition or after the 087 * transition has ended. If the value of {@code interpolator} is changed for 088 * a running {@code Transition}, the animation has to be stopped and started again to 089 * pick up the new value. 090 * <p> 091 * Default interpolator is set to {@link Interpolator#EASE_BOTH}. 092 * 093 * @defaultValue EASE_BOTH 094 */ 095 private ObjectProperty<Interpolator> interpolator; 096 private static final Interpolator DEFAULT_INTERPOLATOR = Interpolator.EASE_BOTH; 097 098 public final void setInterpolator(Interpolator value) { 099 if ((interpolator != null) || (!DEFAULT_INTERPOLATOR.equals(value))) { 100 interpolatorProperty().set(value); 101 } 102 } 103 104 public final Interpolator getInterpolator() { 105 return (interpolator == null) ? DEFAULT_INTERPOLATOR : interpolator.get(); 106 } 107 108 public final ObjectProperty<Interpolator> interpolatorProperty() { 109 if (interpolator == null) { 110 interpolator = new SimpleObjectProperty<Interpolator>( 111 this, "interpolator", DEFAULT_INTERPOLATOR 112 ); 113 } 114 return interpolator; 115 } 116 117 private Interpolator cachedInterpolator; 118 119 /** 120 * Returns the {@link Interpolator}, that was set when the 121 * {@code Transition} was started. 122 * 123 * Changing the {@link #interpolator} of a running {@code Transition} should 124 * have no immediate effect. Instead the running {@code Transition} should 125 * continue to use the original {@code Interpolator} until it is stopped and 126 * started again. 127 * 128 * @return the {@code Interpolator} that was set when this 129 * {@code Transition} was started 130 */ 131 protected Interpolator getCachedInterpolator() { 132 return cachedInterpolator; 133 } 134 135 /** 136 * The constructor of {@code Transition}. 137 * 138 * This constructor allows to define a {@link #targetFramerate}. 139 * 140 * @param targetFramerate 141 * The custom target frame rate for this {@code Transition} 142 */ 143 public Transition(double targetFramerate) { 144 super(targetFramerate); 145 } 146 147 /** 148 * The constructor of {@code Transition}. 149 */ 150 public Transition() { 151 } 152 153 // For testing purposes 154 Transition(AbstractMasterTimer timer) { 155 super(timer); 156 } 157 158 /** 159 * Returns the target {@link Node} for animation of this {@code Transition}. 160 * This method returns {@code node} if it is set, else returns its 161 * {@code parent.getTargetNode()} otherwise null. 162 */ 163 protected Node getParentTargetNode() { 164 return (parent != null && parent instanceof Transition) ? 165 ((Transition)parent).getParentTargetNode() : null; 166 } 167 168 /** 169 * The method {@code interpolate()} has to be provided by implementations of 170 * {@code Transition}. While a {@code Transition} is running, this method is 171 * called in every frame. 172 * 173 * The parameter defines the current position with the animation. At the 174 * start, the fraction will be {@code 0.0} and at the end it will be 175 * {@code 1.0}. How the parameter increases, depends on the 176 * {@link #interpolatorProperty() interpolator}, e.g. if the 177 * {@code interpolator} is {@link Interpolator#LINEAR}, the fraction will 178 * increase linear. 179 * 180 * This method must not be called by the user directly. 181 * 182 * @param frac 183 * The relative position 184 */ 185 protected abstract void interpolate(double frac); 186 187 private double calculateFraction(long currentTicks, long cycleTicks) { 188 final double frac = (double) currentTicks / cycleTicks; 189 return cachedInterpolator.interpolate(0.0, 1.0, frac); 190 } 191 192 @Override 193 boolean impl_startable(boolean forceSync) { 194 return super.impl_startable(forceSync) 195 && ((getInterpolator() != null) || (!forceSync && (cachedInterpolator != null))); 196 } 197 198 @Override 199 void impl_sync(boolean forceSync) { 200 super.impl_sync(forceSync); 201 if (forceSync || (cachedInterpolator == null)) { 202 cachedInterpolator = getInterpolator(); 203 } 204 } 205 206 @Override 207 void impl_playTo(long currentTicks, long cycleTicks) { 208 impl_setCurrentTicks(currentTicks); 209 interpolate(calculateFraction(currentTicks, cycleTicks)); 210 } 211 212 @Override 213 void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump) { 214 impl_setCurrentTicks(currentTicks); 215 if (getStatus() != Status.STOPPED || forceJump) { 216 impl_sync(false); 217 interpolate(calculateFraction(currentTicks, cycleTicks)); 218 } 219 } 220}