1

我正在尝试将 textView 中的 3 个“爆炸”文本动画链接在一起,以依次显示 3 个单词:“Ready”、“Set”和“Go!”。通过“爆炸”,我的意思是文本大小从默认的 0.25f 到默认的 1.00f,而 alpha=0 到 alpha=1。

问题:我能够按预期将第一个单词“Ready”变为“explode”,但下一个单词“Set”没有“explode”,即根本不改变文本大小(只有动画的 alpha 部分有效)。

我的 MainActivity.java 如下。我没有进行第三次“爆炸”,因为如果我能让第二次爆炸,那就是复制和粘贴的问题。

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    public void actionExplode(View view) {

        // .setTextSize() defaults to sp but .getTextSize() defaults to px http://stackoverflow.com/a/3687385/1827488

        String textReady = "Ready";
        final String textSet = "Set";
        final String textGo =  "Go!";

        final TextView questionDisplay = (TextView) findViewById(R.id.textView);
        final float textSizePx = questionDisplay.getTextSize();
        Log.i("actionExplode", "textSizePx=" + textSizePx);

        final float scaleSmall = 0.25f;
        float scaleFull = 1.0f;
        final float fadeOut = 0f;
        float fadeIn = 1f;

        questionDisplay.setAlpha(fadeOut);
        questionDisplay.setText(textReady);
        questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
        Log.i("actionExplode", ".getTextSize()=" + questionDisplay.getTextSize());

        int animateDurationReadySetGo = 1000;
        int animateDurationFudge = 100;

        ObjectAnimator animateReadyFadeIn = ObjectAnimator.ofFloat(questionDisplay, "alpha", fadeOut, fadeIn);
        animateReadyFadeIn.setDuration(animateDurationReadySetGo);
        ObjectAnimator animateReadyX = ObjectAnimator.ofFloat(questionDisplay, "scaleX", scaleFull/scaleSmall);
        animateReadyX.setDuration(animateDurationReadySetGo);
        ObjectAnimator animateReadyY = ObjectAnimator.ofFloat(questionDisplay, "scaleY", scaleFull/scaleSmall);
        animateReadyY.setDuration(animateDurationReadySetGo /* + animateDurationFudge */ );
        animateReadyY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "before .getTextSize()=" + questionDisplay.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                questionDisplay.setText(textSet);
                questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });

        ObjectAnimator animateSetFadeIn = ObjectAnimator.ofFloat(questionDisplay, "alpha", fadeOut, fadeIn);
        animateSetFadeIn.setDuration(animateDurationReadySetGo);
        ObjectAnimator animateSetX = ObjectAnimator.ofFloat(questionDisplay, "scaleX", scaleFull/scaleSmall);
        animateSetX.setDuration(animateDurationReadySetGo);
        ObjectAnimator animateSetY = ObjectAnimator.ofFloat(questionDisplay, "scaleY", scaleFull/scaleSmall);
        animateSetY.setDuration(animateDurationReadySetGo /* + animateDurationFudge */ );
        animateSetY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "before .getTextSize()=" + questionDisplay.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                questionDisplay.setText(textGo);
                questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });

        AnimatorSet animateReadySetGo = new AnimatorSet();
        animateReadySetGo.playTogether(animateReadyX, animateReadyY, animateReadyFadeIn);
        animateReadySetGo.playTogether(animateSetX, animateSetY, animateSetFadeIn);
        animateReadySetGo.playSequentially(animateReadyY, animateSetY);
        animateReadySetGo.start();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

这就是日志显示的内容。没有意义的是:1)为什么“之前”行显示 43.75 而应该显示 175.0?和 2)为什么“之后”行显示 43.75 但文本大小不缩小?

I/actionExplode: textSizePx=175.0
I/actionExplode: .getTextSize()=43.75
I/onAnimationEnd: before .getTextSize()=43.75
I/onAnimationEnd: after .getTextSize()=43.75
I/onAnimationEnd: before .getTextSize()=43.75
I/onAnimationEnd: after .getTextSize()=43.75

我的activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.plaudev.explodingtext.MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:text="@string/textView"
        android:id="@+id/textView"
        android:fontFamily="casual"
        android:textSize="50sp"
        android:textStyle="normal|bold"
        android:textAlignment="center"
        android:gravity="center" />

    <Button
        android:text="@string/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"
        android:id="@+id/button"
        android:background="@color/colourTransparent"
        android:textAllCaps="false"
        android:textSize="25sp"
        android:textStyle="normal|bold"
        android:fontFamily="casual"
        android:onClick="actionExplode"
        android:textColor="@android:color/holo_green_dark" />
</RelativeLayout>

更新 1:仍未找到解决方案,但想注意此行为。如果我重写actionExplode()为递归运行并使用其他东西作为 onClick 来启动,所以我的 MainActivity 类如下,那么我可以获得 3 个“爆炸”链,但每个都从一个连续较小的文本大小开始,如图所示下面的附加日志。似乎通过制作插座questionDisplay final以便听众或计时器可以使用它来链接动画以某种方式导致插座保留文本大小,即使我仍然可以更改其文本(即仅选择性地final)。因此,我也尝试了一些变体(如代码注释中所述),但没有一个比变体 A 更接近预期的行为。

public class MainActivity extends AppCompatActivity {

    String[] explosionChain = {"Ready", "Set", "Go!"};
    int explosionIndex = 0;
    int animateDurationExplosion = 1000;
    int animateDurationFudge = 100;

    public void actionExplode(final float textSizeFullPx, final int explosionIndex) {

        final TextView questionDisplay = (TextView) findViewById(R.id.textView);
        float textSizePx = questionDisplay.getTextSize();
        Log.i("actionExplode", "textSizeFullPx=" + textSizeFullPx + ", explosionIndex=" + explosionIndex + ", textSizePx=" + textSizePx);

        float scaleSmall = 0.25f;
        float scaleFull = 1.0f;
        float fadeOut = 0f;
        float fadeIn = 1f;

        questionDisplay.setAlpha(fadeOut);
        questionDisplay.setText(explosionChain[explosionIndex]);
        // variation A
        //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizeFullPx * scaleSmall);
        // variation B
        questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
        Log.i("actionExplode", ".getTextSize()=" + questionDisplay.getTextSize());

        ObjectAnimator animateFadeIn = ObjectAnimator.ofFloat(questionDisplay, "alpha", fadeOut, fadeIn);
        animateFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateScaleX = ObjectAnimator.ofFloat(questionDisplay, "scaleX", scaleFull/scaleSmall);
        animateScaleX.setDuration(animateDurationExplosion);
        ObjectAnimator animateScaleY = ObjectAnimator.ofFloat(questionDisplay, "scaleY", scaleFull/scaleSmall);
        animateScaleY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );

        AnimatorSet animateExplosion = new AnimatorSet();
        animateExplosion.playTogether(animateScaleX, animateScaleY, animateFadeIn);
        animateExplosion.start();

        CountDownTimer explodeNext = new CountDownTimer(animateDurationExplosion, animateDurationExplosion) {
            @Override
            public void onTick(long millisUntilFinished) {
            }
            @Override
            public void onFinish() {
                // variation C
                Log.i("onFinish", ".getTextSize()=" + questionDisplay.getTextSize());
                // variation D
                //Log.i("onFinish", "before .getTextSize()=" + questionDisplay.getTextSize());
                //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizeFullPx);
                //Log.i("onFinish", "after .getTextSize()=" + questionDisplay.getTextSize());
                if ((explosionIndex + 1) < explosionChain.length) {
                    actionExplode(textSizeFullPx, explosionIndex + 1);
                }
            }
        };
        explodeNext.start();
    }

    public void startChainExplosion(View view) {

        final TextView questionDisplay = (TextView) findViewById(R.id.textView);
        final float textSizeFullPx = questionDisplay.getTextSize();
        Log.i("startChainExplosion", "explosionIndex=" + explosionIndex + ", textSizeFullPx=" + textSizeFullPx);

        actionExplode(textSizeFullPx, explosionIndex);

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

上面更新的代码产生了这个日志:

I/startChainExplosion: explosionIndex=0, textSizeFullPx=175.0
I/actionExplode: textSizeFullPx=175.0, explosionIndex=0, textSizePx=175.0
I/actionExplode: .getTextSize()=43.75
I/onFinish: .getTextSize()=43.75
I/actionExplode: textSizeFullPx=175.0, explosionIndex=1, textSizePx=43.75
I/actionExplode: .getTextSize()=10.9375
I/onFinish: .getTextSize()=10.9375
I/actionExplode: textSizeFullPx=175.0, explosionIndex=2, textSizePx=10.9375
I/actionExplode: .getTextSize()=2.734375
I/onFinish: .getTextSize()=2.734375

更新 2:按照@Xaver 的建议,尝试将其用作 onClick。但结果与我最初的尝试相同,即“Ready”爆炸但“Set”和“Go!” 不。此外,在所有动画完成后,文本大小变得非常大(我猜是 175px * 4)。更新代码和日志如下。我有一种感觉,我需要每个单词都有自己的 textView 以避免这个文本大小保留问题。

public void explodeSequentially(View view) {

        String textReady = "Ready";
        final String textSet = "Set";
        final String textGo =  "Go!";

        final TextView questionDisplay = (TextView) findViewById(R.id.textView);
        float textSizePx = questionDisplay.getTextSize();
        Log.i("explodeSequentially", "textSizePx=" + textSizePx);

        float scaleSmall = 0.25f;
        float scaleFull = 1.0f;
        float fadeOut = 0f;
        float fadeIn = 1f;

        questionDisplay.setAlpha(fadeOut);
        questionDisplay.setText(textReady);
        questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
        Log.i("explodeSequentially", ".getTextSize()=" + questionDisplay.getTextSize());

        ObjectAnimator animateReadyFadeIn = ObjectAnimator.ofFloat(questionDisplay, "alpha", fadeOut, fadeIn);
        animateReadyFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateReadyX = ObjectAnimator.ofFloat(questionDisplay, "scaleX", scaleFull/scaleSmall);
        animateReadyX.setDuration(animateDurationExplosion);
        ObjectAnimator animateReadyY = ObjectAnimator.ofFloat(questionDisplay, "scaleY", scaleFull/scaleSmall);
        animateReadyY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );
        animateReadyY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "before .getTextSize()=" + questionDisplay.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                questionDisplay.setText(textSet);
                //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                //Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });
        AnimatorSet animateReady = new AnimatorSet();
        animateReady.playTogether(animateReadyX, animateReadyY, animateReadyFadeIn);

        ObjectAnimator animateSetFadeIn = ObjectAnimator.ofFloat(questionDisplay, "alpha", fadeOut, fadeIn);
        animateSetFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateSetX = ObjectAnimator.ofFloat(questionDisplay, "scaleX", scaleFull/scaleSmall);
        animateSetX.setDuration(animateDurationExplosion);
        ObjectAnimator animateSetY = ObjectAnimator.ofFloat(questionDisplay, "scaleY", scaleFull/scaleSmall);
        animateSetY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );
        animateSetY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "before .getTextSize()=" + questionDisplay.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                questionDisplay.setText(textGo);
                //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                //Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });
        AnimatorSet animateSet = new AnimatorSet();
        animateSet.playTogether(animateSetX, animateSetY, animateSetFadeIn);

        ObjectAnimator animateGoFadeIn = ObjectAnimator.ofFloat(questionDisplay, "alpha", fadeOut, fadeIn);
        animateGoFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateGoX = ObjectAnimator.ofFloat(questionDisplay, "scaleX", scaleFull/scaleSmall);
        animateGoX.setDuration(animateDurationExplosion);
        ObjectAnimator animateGoY = ObjectAnimator.ofFloat(questionDisplay, "scaleY", scaleFull/scaleSmall);
        animateGoY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );
        animateGoY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "before .getTextSize()=" + questionDisplay.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                questionDisplay.setText("Here is the question!");
                //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                //Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });
        AnimatorSet animateGo = new AnimatorSet();
        animateGo.playTogether(animateGoX, animateGoY, animateGoFadeIn);

        AnimatorSet animateReadySetGo = new AnimatorSet();
        animateReadySetGo.playSequentially(animateReady, animateSet, animateGo);
        animateReadySetGo.start();
    }

和日志

I/explodeSequentially: textSizePx=175.0
I/explodeSequentially: .getTextSize()=43.75
I/onAnimationEnd: before .getTextSize()=43.75
I/onAnimationEnd: before .getTextSize()=43.75
I/onAnimationEnd: before .getTextSize()=43.75
4

1 回答 1

1

我的怀疑是正确的。每当在插座上使用时,s上的文本大小textView都会徘徊final,如果我想链接动画,这种使用似乎是不可避免的。但是,通过将我想要“爆炸”的每个单词拆分成自己的单词textView,至少我可以让“爆炸”效果按预期顺序工作。

以下代码将只实现一次预期的动画序列,即下次单击按钮时,动画序列将从 43.75px 而不是最初的 175.0px 开始,并且每次单击时会继续以 0.25f 因子减小。我将修改代码以动态创建和销毁textViews 以便稍后解决(现在在下面更新)。

新的 MainActivity.java:

public class MainActivity extends AppCompatActivity {

    public void explodeThreeTextViews (View view) {

        int animateDurationExplosion = 1000;
        float scaleSmall = 0.25f;
        float scaleFull = 1.0f;
        float fadeOut = 0f;
        final float fadeIn = 1f;

        final TextView tvQuestion = (TextView) findViewById(R.id.question);
        final TextView tvReady = (TextView) findViewById(R.id.ready);
        final TextView tvSet = (TextView) findViewById(R.id.set);
        final TextView tvGo = (TextView) findViewById(R.id.go);

        float tvReadySizePx = tvReady.getTextSize();
        float tvSetSizePx = tvSet.getTextSize();
        float tvGoSizePx = tvGo.getTextSize();
        Log.i("explodeThreeTextViews", "tvReadySizePx=" + tvReadySizePx + ", tvSetSizePx=" + tvSetSizePx + ", tvGoSizePx=" + tvGoSizePx);

        tvQuestion.setAlpha(fadeOut);
        tvReady.setAlpha(fadeOut);
        tvSet.setAlpha(fadeOut);
        tvGo.setAlpha(fadeOut);

        tvQuestion.setText("The question!");
        tvReady.setText("Ready");
        tvSet.setText("Set");
        tvGo.setText("Go!");

        tvQuestion.setVisibility(View.GONE);
        tvReady.setVisibility(View.VISIBLE);

        tvReady.setTextSize(TypedValue.COMPLEX_UNIT_PX, tvReadySizePx * scaleSmall);
        tvSet.setTextSize(TypedValue.COMPLEX_UNIT_PX, tvSetSizePx * scaleSmall);
        tvGo.setTextSize(TypedValue.COMPLEX_UNIT_PX, tvGoSizePx * scaleSmall);
        Log.i("explodeThreeTextViews", "tvReady.getTextSize=" + tvReady.getTextSize() + ", tvSet.getTextSize=" + tvSet.getTextSize() + ", tvGo.getTextSize=" + tvGo.getTextSize());

        ObjectAnimator animateReadyFadeIn = ObjectAnimator.ofFloat(tvReady, "alpha", fadeOut, fadeIn);
        animateReadyFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateReadyX = ObjectAnimator.ofFloat(tvReady, "scaleX", scaleFull/scaleSmall);
        animateReadyX.setDuration(animateDurationExplosion);
        ObjectAnimator animateReadyY = ObjectAnimator.ofFloat(tvReady, "scaleY", scaleFull/scaleSmall);
        animateReadyY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );
        animateReadyY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "tvReady.getTextSize()=" + tvReady.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                tvReady.setVisibility(View.GONE);
                tvSet.setVisibility(View.VISIBLE);
                //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                //Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });
        AnimatorSet animateReady = new AnimatorSet();
        animateReady.playTogether(animateReadyX, animateReadyY, animateReadyFadeIn);

        ObjectAnimator animateSetFadeIn = ObjectAnimator.ofFloat(tvSet, "alpha", fadeOut, fadeIn);
        animateSetFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateSetX = ObjectAnimator.ofFloat(tvSet, "scaleX", scaleFull/scaleSmall);
        animateSetX.setDuration(animateDurationExplosion);
        ObjectAnimator animateSetY = ObjectAnimator.ofFloat(tvSet, "scaleY", scaleFull/scaleSmall);
        animateSetY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );
        animateSetY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "tvSet.getTextSize()=" + tvSet.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                tvSet.setVisibility(View.GONE);
                tvGo.setVisibility(View.VISIBLE);
                //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                //Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });
        AnimatorSet animateSet = new AnimatorSet();
        animateSet.playTogether(animateSetX, animateSetY, animateSetFadeIn);

        ObjectAnimator animateGoFadeIn = ObjectAnimator.ofFloat(tvGo, "alpha", fadeOut, fadeIn);
        animateGoFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateGoX = ObjectAnimator.ofFloat(tvGo, "scaleX", scaleFull/scaleSmall);
        animateGoX.setDuration(animateDurationExplosion);
        ObjectAnimator animateGoY = ObjectAnimator.ofFloat(tvGo, "scaleY", scaleFull/scaleSmall);
        animateGoY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );
        animateGoY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", "tvGo.getTextSize()=" + tvGo.getTextSize());
                //questionDisplay.setAlpha(fadeOut);
                tvGo.setVisibility(View.GONE);
                tvQuestion.setVisibility(View.VISIBLE);
                tvQuestion.setAlpha(fadeIn);
                //questionDisplay.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
                //Log.i("onAnimationEnd", "after .getTextSize()=" + questionDisplay.getTextSize());
            }
        });
        AnimatorSet animateGo = new AnimatorSet();
        animateGo.playTogether(animateGoX, animateGoY, animateGoFadeIn);

        AnimatorSet animateReadySetGo = new AnimatorSet();
        animateReadySetGo.playSequentially(animateReady, animateSet, animateGo);
        animateReadySetGo.start();
    }

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

新的activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.plaudev.explodingtext.MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:id="@+id/questionDisplay">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@string/textView"
            android:id="@+id/question"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:textAlignment="center"
            android:gravity="center"
            android:layout_weight="1"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@string/textView"
            android:id="@+id/ready"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:textAlignment="center"
            android:gravity="center"
            android:layout_weight="1"
            android:visibility="gone"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@string/textView"
            android:id="@+id/set"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:textAlignment="center"
            android:gravity="center"
            android:layout_weight="1"
            android:visibility="gone"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@string/textView"
            android:id="@+id/go"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:textAlignment="center"
            android:gravity="center"
            android:layout_weight="1"
            android:visibility="gone"/>

        <Button
            android:text="@string/button"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:id="@+id/button"
            android:background="@color/colourTransparent"
            android:textAllCaps="false"
            android:textSize="25sp"
            android:textStyle="normal|bold"
            android:fontFamily="casual"
            android:onClick="explodeThreeTextViews"
            android:textColor="@android:color/holo_green_dark"
            android:layout_weight="1" />

    </LinearLayout>

</RelativeLayout>

运行时的日志:

I/explodeThreeTextViews: tvReadySizePx=175.0, tvSetSizePx=175.0, tvGoSizePx=175.0
I/explodeThreeTextViews: tvReady.getTextSize=43.75, tvSet.getTextSize=43.75, tvGo.getTextSize=43.75
I/onAnimationEnd: tvReady.getTextSize()=43.75
I/onAnimationEnd: tvSet.getTextSize()=43.75
I/onAnimationEnd: tvGo.getTextSize()=43.75

更新:使用动态创建和销毁的视图,可以根据之前尝试的递归方法重复使用。

更新 MainActivity.java - 您可以选择使用动画侦听器或 CountDownTimer 来链接“爆炸”:

public class MainActivity extends AppCompatActivity {

    // constants
    String[] explosionChain = {"Ready", "Set", "Go!"};
    float scaleSmall = 0.25f;
    float scaleFull = 1.0f;
    float fadeOut = 0f;
    float fadeIn = 1f;
    int animateDurationExplosion = 1000;
    int animateDurationFudge = 100;

    // variables
    float textSizeFullPx;
    TextView[] explosionViews;
    int explosionIndex;

    public void prepareChainExplosions(View view) {

        //String typeface = "casual";

        LinearLayout questionDisplay = (LinearLayout) findViewById(R.id.questionDisplay);
        TextView questionView = (TextView) findViewById(R.id.questionView);
        textSizeFullPx = questionView.getTextSize();
        Log.i("prepareChainExplosions", "textSizeFullPx=" + textSizeFullPx);

        explosionViews = new TextView[explosionChain.length];
        for (int i = 0; i < explosionViews.length; i++) {
            explosionViews[i] = new TextView(questionDisplay.getContext());
            explosionViews[i].setVisibility(View.GONE);
            explosionViews[i].setAlpha(fadeOut);
            //explosionViews[i].setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, 1f));
            explosionViews[i].setLayoutParams(questionView.getLayoutParams());
            //explosionViews[i].setGravity(Gravity.CENTER);
            explosionViews[i].setGravity(questionView.getGravity());
            //explosionViews[i].setTypeface(Typeface.create(typeface, Typeface.BOLD));
            explosionViews[i].setTypeface(questionView.getTypeface());
            explosionViews[i].setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizeFullPx);
            explosionViews[i].setText(explosionChain[i]);
            questionDisplay.addView(explosionViews[i]);
        }
        Log.i("prepareChainExplosions", "questionDisplay.getChildCount()=" + questionDisplay.getChildCount());
    }

public void actionExplode(final int explosionIndex) {

        final TextView questionView = (TextView) findViewById(R.id.questionView);
        final TextView explodingView = explosionViews[explosionIndex];
        float textSizePx = explodingView.getTextSize();
        Log.i("actionExplode", "explosionIndex=" + explosionIndex + ", textSizePx=" + textSizePx);

        explodingView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSizePx * scaleSmall);
        Log.i("actionExplode", ".getTextSize()=" + explodingView.getTextSize());

        if (explosionIndex == 0) questionView.setVisibility(View.GONE);
        explodingView.setVisibility(View.VISIBLE);

        ObjectAnimator animateFadeIn = ObjectAnimator.ofFloat(explodingView, "alpha", fadeOut, fadeIn);
        animateFadeIn.setDuration(animateDurationExplosion);
        ObjectAnimator animateScaleX = ObjectAnimator.ofFloat(explodingView, "scaleX", scaleFull/scaleSmall);
        animateScaleX.setDuration(animateDurationExplosion);
        ObjectAnimator animateScaleY = ObjectAnimator.ofFloat(explodingView, "scaleY", scaleFull/scaleSmall);
        animateScaleY.setDuration(animateDurationExplosion /* + animateDurationFudge */ );
        animateScaleY.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Log.i("onAnimationEnd", ".getTextSize()=" + explodingView.getTextSize());
                explodingView.setVisibility(View.GONE);
                if ((explosionIndex + 1) < explosionChain.length) {
                    actionExplode(explosionIndex + 1);
                } else {
                    questionView.setVisibility(View.VISIBLE);
                }
            }
        });

        AnimatorSet animateExplosion = new AnimatorSet();
        animateExplosion.playTogether(animateScaleX, animateScaleY, animateFadeIn);
        animateExplosion.start();

        /*
        CountDownTimer explodeNext = new CountDownTimer(animateDurationExplosion, animateDurationExplosion) {
            @Override
            public void onTick(long millisUntilFinished) {
            }
            @Override
            public void onFinish() {
                Log.i("onFinish", ".getTextSize()=" + explodingView.getTextSize());
                explodingView.setVisibility(View.GONE);
                if ((explosionIndex + 1) < explosionChain.length) {
                    actionExplode(explosionIndex + 1);
                } else {
                    questionView.setVisibility(View.VISIBLE);
                }
            }
        };
        explodeNext.start();
        */
    }

    public void startChainExplosions(View view) {

        prepareChainExplosions(view);
        explosionIndex = 0;
        Log.i("startChainExplosions", "explosionIndex=" + explosionIndex);

        actionExplode(explosionIndex);

        CountDownTimer cleanChainExplosions = new CountDownTimer(animateDurationExplosion * explosionChain.length, animateDurationExplosion) {
            @Override
            public void onTick(long millisUntilFinished) {
            }
            @Override
            public void onFinish() {
                for (int i = 0; i < explosionViews.length; i++) {
                    ((ViewManager) explosionViews[i].getParent()).removeView(explosionViews[i]);
                }
                LinearLayout questionDisplay = (LinearLayout) findViewById(R.id.questionDisplay);
                Log.i("startChainExplosions", "questionDisplay.getChildCount()=" + questionDisplay.getChildCount());
            }
        };
        cleanChainExplosions.start();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

更新了 activity_main.xml -textViews保留了一些冗余以向后兼容之前的代码。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.plaudev.explodingtext.MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:id="@+id/questionDisplay">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/textView"
            android:id="@+id/questionView"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:layout_weight="1"
            android:gravity="center" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@string/textView"
            android:id="@+id/readyView"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:textAlignment="center"
            android:gravity="center"
            android:layout_weight="1"
            android:visibility="gone"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@string/textView"
            android:id="@+id/setView"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:textAlignment="center"
            android:gravity="center"
            android:layout_weight="1"
            android:visibility="gone"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="@string/textView"
            android:id="@+id/goView"
            android:fontFamily="casual"
            android:textSize="50sp"
            android:textStyle="normal|bold"
            android:textAlignment="center"
            android:gravity="center"
            android:layout_weight="1"
            android:visibility="gone"/>

    </LinearLayout>

    <Button
        android:text="@string/button"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:id="@+id/button"
        android:background="@color/colourTransparent"
        android:textAllCaps="false"
        android:textSize="25sp"
        android:textStyle="normal|bold"
        android:fontFamily="casual"
        android:onClick="startChainExplosions"
        android:textColor="@android:color/holo_green_dark"
        android:layout_below="@+id/questionDisplay"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

</RelativeLayout>

更新日志:

I/prepareChainExplosions: textSizeFullPx=175.0
I/prepareChainExplosions: questionDisplay.getChildCount()=7
I/startChainExplosions: explosionIndex=0
I/actionExplode: explosionIndex=0, textSizePx=175.0
I/actionExplode: .getTextSize()=43.75
I/onAnimationEnd: .getTextSize()=43.75
I/actionExplode: explosionIndex=1, textSizePx=175.0
I/actionExplode: .getTextSize()=43.75
I/onAnimationEnd: .getTextSize()=43.75
I/actionExplode: explosionIndex=2, textSizePx=175.0
I/actionExplode: .getTextSize()=43.75
I/startChainExplosions: questionDisplay.getChildCount()=4
I/onAnimationEnd: .getTextSize()=43.75
于 2016-10-25T18:12:12.853 回答