Гладкая jQuery-подобная анимация в GWT
Я играю с классом GWT Animation как упражнение. Моя цель - не создавать еще одну библиотеку виджета/анимации для GWT. Кроме того, я хорошо знаю, что есть много библиотек, которые это делают. То, что я пытаюсь сделать, это узнать, как это можно сделать, а не как использовать некоторую библиотеку. Это только для образовательных целей....
С учетом сказанного я реализовал простой класс, который выполняет 4 разных анимации на некоторых виджетах: затухает, исчезает, скользит и выворачивается (после анимационной модели jQuery). См. Код ниже, как я его реализовал.
LIVE DEMO: http://www.rodrigo-silveira.com/gwt-custom-animation/
Мой вопрос: как я могу [и успешно] останавливать анимацию, как только запускается другая, и продолжать текущую анимацию, где старая остановилась?
Например, если slideIn() на полпути, когда вызывается функция slideOut(), как я могу начать выскакивать из естественной высоты виджета на 50%? Я попробовал сохранить переменную-член, которая всегда отслеживает текущий прогресс, поэтому я могу использовать это в новой анимации, но, похоже, не все правильно. Любые идеи?
import com.google.gwt.animation.client.Animation;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Element;
public class RokkoAnim extends Animation {
private Element element;
private int currentOp;
private final static int FADE_OUT = 0;
private final static int FADE_IN = 1;
private final static int SLIDE_IN = 2;
private final static int SLIDE_OUT = 3;
public RokkoAnim(Element element) {
this.element = element;
}
public void fadeOut(int durationMilli) {
cancel();
currentOp = RokkoAnim.FADE_OUT;
run(durationMilli);
}
public void fadeIn(int durationMilli) {
cancel();
currentOp = RokkoAnim.FADE_IN;
run(durationMilli);
}
public void slideIn(int durationMilli) {
cancel();
currentOp = RokkoAnim.SLIDE_IN;
run(durationMilli);
}
public void slideOut(int durationMilli) {
cancel();
currentOp = RokkoAnim.SLIDE_OUT;
run(durationMilli);
}
@Override
protected void onUpdate(double progress) {
switch (currentOp) {
case RokkoAnim.FADE_IN:
doFadeIn(progress);
break;
case RokkoAnim.FADE_OUT:
doFadeOut(progress);
break;
case RokkoAnim.SLIDE_IN:
doSlideIn(progress);
break;
case RokkoAnim.SLIDE_OUT:
doSlideOut(progress);
break;
}
}
private void doFadeOut(double progress) {
element.getStyle().setOpacity(1.0d - progress);
}
private void doFadeIn(double progress) {
element.getStyle().setOpacity(progress);
}
private void doSlideIn(double progress) {
double height = element.getScrollHeight();
element.getStyle().setHeight(height * (1.0d - progress), Unit.PX);
}
private void doSlideOut(double progress) {
// Hard coded value. How can I find out what
// the element max natural height is if it
// currently set to height: 0 ?
element.getStyle().setHeight(200 * progress, Unit.PX);
}
}
Использование
// 1. Get some widget
FlowPanel div = new FlowPanel();
// 2. Instantiate the animation, passing the widget
RokkoAnim anim = new RokkoAnim(div.getElement());
// 3. Perform the animation
// >> inside mouseover event of some widget:
anim.fadeIn(1500);
// >> inside mouseout event of some widget:
anim.fadeOut(1500);
Ответы
Ответ 1
Вам нужно обновить непрозрачность на основе текущего значения (эквивалентно назначениям +=
или -=
):
private void doFadeOut(double progress) {
double opacity = element.getStyle().getOpacity();
element.getStyle().setOpacity(opacity - 1.0d - progress);
}
private void doFadeIn(double progress) {
double opacity = element.getStyle().getOpacity();
element.getStyle().setOpacity(opacity + progress);
}
Ответ 2
- Добавить метод экземпляра bool, отменивший ваш класс annimation
- Запускать аннулирование, если не отменено.
-
Добавьте метод cancelAnnimation и вызовите этот метод каждый раз, когда начинается новая аннулирование.
private bool canceled = false;
public void cancelAnnimation() {
canceled = true;
}
private void doFadeOut(double progress) {
if(!canceled) {
element.getStyle().setOpacity(1.0d - progress);
}
}
... etc.
Таким образом, вы можете остановить анимацию. Но теперь вам нужно запустить новую анимацию с текущей точки. Поэтому лучше было снова изменить класс.
- добавить две переменные экземпляра currentProgress и offset (double)
- добавьте двойное смещение к конструктору
- return currentProgress при аннулировании аннулирования.
-
Запустите новую анимацию со смещением от первой анимации.
private bool canceled = false;
private double currentProgress = 0;
private double offset = 0;
public RokkoAnim(Element element, double offset) {
this.element = element;
this.offset = offset;
}
public double cancelAnimation() {
canceled = true;
return currentProgress;
}
private void doFadeOut(double progress) {
if(!canceled && ((progress + offset) <= 1)) {
element.getStyle().setOpacity(1.0d - (progress+offset));
currentProgress = progress+offset;
}
}
... etc.
double offset = anim1.cancelAnimation();
RokkoAnim anim2 = new RokkoAnim(div.getElement(), offset);
Ответ 3
для скользящих входов и выходов Я изменил свой класс, чтобы использовать экранные сетки виджета:
public class WidgetAnimation extends Animation {
private Element element;
private int currentOp;
private int startX=-1;
private int finalX=-1;
private final static int FADE_OUT = 0;
private final static int FADE_IN = 1;
private final static int SLIDE_IN = 2;
private final static int SLIDE_OUT = 3;
public WidgetAnimation(Element element) {
this.element = element;
}
public void fadeOut(int durationMilli) {
cancel();
currentOp = WidgetAnimation.FADE_OUT;
run(durationMilli);
}
public void fadeIn(int durationMilli) {
cancel();
currentOp = WidgetAnimation.FADE_IN;
run(durationMilli);
}
public void slideIn(int durationMilli) {
cancel();
currentOp = WidgetAnimation.SLIDE_IN;
run(durationMilli);
}
public void slideOut(int durationMilli) {
cancel();
currentOp = WidgetAnimation.SLIDE_OUT;
run(durationMilli);
}
@Override
protected void onUpdate(double progress) {
switch (currentOp) {
case WidgetAnimation.FADE_IN:
doFadeIn(progress);
break;
case WidgetAnimation.FADE_OUT:
doFadeOut(progress);
break;
case WidgetAnimation.SLIDE_IN:
doSlideIn(progress);
break;
case WidgetAnimation.SLIDE_OUT:
doSlideOut(progress);
break;
}
}
private void doFadeOut(double progress) {
element.getStyle().setOpacity(1.0d - progress);
}
private void doFadeIn(double progress) {
element.getStyle().setOpacity(progress);
}
private void doSlideIn(double progress) {
if(startX==-1){
finalX = element.getAbsoluteLeft();
startX = - Window.getClientWidth();
}
int positionX = (int) (startX + (progress * (this.finalX - startX)));
this.element.getStyle().setLeft(positionX, Unit.PX);
}
private void doSlideOut(double progress) {
if(startX==-1){
startX = element.getAbsoluteLeft();
finalX = - Window.getClientWidth();
}
int positionX = (int) (startX + (progress * (this.finalX - startX)));
GWT.log("StartX:" + startX);
GWT.log("finalX:" + finalX);
GWT.log("positionX:" + positionX);
GWT.log("progress:" + progress);
this.element.getStyle().setLeft(positionX, Unit.PX);
}
}
Я выскальзываю и горизонтально, но вы можете изменить код.
Я надеюсь, что это поможет.