Android如何在textView中链接“爆炸”文本动画?

时间:2016-10-25 05:17:56

标签: android textview scale objectanimator animatorset

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

问题:我能够按预期获得第一个单词“Ready”以“爆炸”,但下一个单词“Set”不会“爆炸”,即根本不会改变文本大小(只有动画的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

1 个答案:

答案 0 :(得分:1)

我怀疑是对的。 textView上的文字大小会在插座上使用final时停留,如果我想链接动画,这种使用似乎是不可避免的。然而,通过将我想要“爆炸”的每个单词分成它自己的textView,至少我可以使“爆炸”效果按预期顺序工作。

以下代码只能实现预期的动画序列一次,即下次单击该按钮时,动画序列将从43.75px开始,而不是从初始的175.0px开始,并且每隔一段时间继续减少0.25f因子你点击了。我将修改代码以动态创建&amp;销毁textView以稍后解决(现在更新)。

新的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

更新:动态创建&amp;基于先前尝试过的递归方法,销毁视图以实现重复使用。

更新了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