多项Android TransitionDrawable

14

我想在Android中创建一个带文本和背景图片的按钮。背景图片应该每隔X时间交替淡入淡出。

我已经使用TransitionDrawable和两张图片使其工作。

但是我无法让它使用超过2张图片。

我所拥有的:

在Java代码中,我创建了一个按钮并设置了背景(这是在XML中定义的TransitionDrawable)。然后我开始过渡。

final Button b = new Button(getApplicationContext());
b.setTextColor(getResources().getColor(R.color.white));
b.setText("Some text");
b.setBackgroundDrawable(getResources().getDrawable(R.drawable.tile));
StateListDrawable background = (StateListDrawable) b.getBackground();
TransitionDrawable td = (TransitionDrawable) background.getCurrent();
td.startTransition(2000);

我在tile.xml文件中定义了XML。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" >
        <shape>
            <solid
                android:color="#449def" />
        </shape>
    </item>
    <item android:drawable="@drawable/transition">
        <shape>
            <solid
                android:color="#0000ff" />
        </shape>
    </item>
</selector> 

最后是一个transition.xml文件

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android"     android:oneshot="false">
  <item android:drawable="@drawable/desert"/> 
  <item android:drawable="@drawable/hydrangeas" /> 
  <item android:drawable="@drawable/jellyfish" /> 
</transition> 

现在的效果是,当我启动应用程序时,沙漠图像会被显示。这个图像像应该一样淡入到绣球花图像中。但是水母图像从未显示。

在TransitionDrawables的文档中,说明可以指定多于2个的可绘制对象,但我无法让其正常工作。

我也尝试了不使用任何XML,而是使用纯JAVA,但是结果完全相同 :-(


1
选择用词不当。我刚刚查看了TransitionDrawable的代码,它只在两个可绘制对象之间淡入淡出,而忽略其他所有图层。 - user
也许你可以简单地使用两个TransitionDrawables,一个包含第一个和第二个可绘制对象,另一个包含相同的第二个可绘制对象加上第三个可绘制对象。 - user
@RobGThai,你找到如何检测过渡是否完成的方法了吗? - ecem
@ecem 目前还没有什么进展。我正在考虑创建自己的 TransitionDrawable 版本。但这方面的事情也不太顺利。 - RobGThai
@RobGThai 我明白了,我在考虑创建一个线程,在过渡时间等待它,然后用新的TransitionDrawable替换它,你认为这样行得通吗? - ecem
显示剩余5条评论
6个回答

7

您可以通过使用处理程序来完成

mAnimateImage is your button

int DrawableImage[] = {R.drawable.back_red, R.drawable.back_green, R.drawable.back_purple};

final Handler handler = new Handler();
    final int[] i = {0};
    final int[] j = {1};
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Resources res = getApplicationContext().getResources();
                    TransitionDrawable out = new TransitionDrawable(new Drawable[]{res.getDrawable(DrawableImage[i[0]]), res.getDrawable(DrawableImage[j[0]])});
                    out.setCrossFadeEnabled(true);
                    mAnimateImage.setBackgroundDrawable(out);
                    out.startTransition(4000);
                    i[0]++;
                    j[0]++;
                    if (j[0] == DrawableImage.length) {
                        j[0] = 0;
                    }
                    if (i[0] == DrawableImage.length) {
                        i[0] = 0;
                    }
                    handler.postDelayed(this, 8000);
                }
            });
        }
    }, 0);

完美!只有一件事 - 由于已被弃用,请考虑使用ContextCompat.getDrawable替换getDrawable。 - Mohit Singh

6
根据官方文档,TransitionDrawable 只能在两个层之间进行淡入淡出效果。引用自官方 Android 参考文档的说明如下:
LayerDrawables 的扩展,旨在实现第一层和第二层之间的渐变效果。要启动过渡,请调用 startTransition(int)。要仅显示第一层,请调用 resetTransition()。
如果你没有仔细阅读,由于它扩展了 LayerDrawables,而 LayerDrawables 可以有多个层,因此可能会期望您可以在 N 层之间进行淡化。但是很明显,startTransition 显示第二层,resetTransition 显示第一层。
我建议您自己实现多个转换。我会使用两个图像并对它们进行动画处理。您可能需要手动设置可绘制对象,但应该是非常简单的代码。

实际上对我来说发生的情况是,它能正常播放第一个转换,然后当我再次调用 startTransition 时,它会跳到第一个可绘制对象并回到第二个可绘制对象。 - CaseyB
3
没错!我已经审核了文档并更新了答案。文档中明确说明它只适用于两层。 - shalafi

4

在附录运作时间中,您可以动态更改图片。

在您的TransitionDrawable上使用td.setDrawableByLayerId(td.getId(1), drawable)

TransitionDrawable transitionDrawable = (TransitionDrawable) myImage
                            .getDrawable();
transitionDrawable.setDrawableByLayerId(transitionDrawable.getId(1), getResources()
                            .getDrawable(R.drawable.c));

1
您只能使用TransitionDrawable过渡最多两张图片。要处理超过两张图片,您可以扩展LayerDrawable并实现自己的TransitionDrawable这里是已准备好的自定义TransitionDrawable实现,可用于处理超过两张图片。
您可以在Github上查看完整的示例以及gif演示。

0

不需要使用处理程序,使用协程比使用处理程序更高效和更清晰,并且作为奖励,您可以在任意数量的可绘制对象之间进行转换:

    /**
     * Run multitransition animation on a view.
     *
     * @param drawableIds The drawables to load into the view, one after the other
     * @param delayBetweenTransitions the number of milliseconds to transition from one drawable to the next
     * @param viewToAnimate The view to animate.
     */
    fun runMultitransitionAnimation(@DrawableRes vararg drawableIds: Int, 
                                    delayBetweenTransitions : Int, 
                                    viewToAnimate : View) {
        CoroutineScope(Dispatchers.Main).launch(Dispatchers.Main.immediate) {
            val delay = SOME_INTEGER_MILLISECONDS
            for (i in 0 until drawableIds.size-1) {
                val nextTransition = TransitionDrawable(arrayOf(
                    context.getDrawable(drawableIds[i]),
                    context.getDrawable(drawableIds[i+1])))
                ))
                nextTransition.isCrossFadeEnabled = true
                viewToAnimate.background = nextTransition
                nextTransition.startTransition(delayBetweenTransitions)
                delay(delayBetweenTransitions*2)
            }
        }
    }

-1

每次迭代都需要创建一个新的TransitionDrawable。

这将逐步增加您添加的所有图像的索引,您可以拥有任意数量的图像...

private Handler handler = new Handler();

private void startImageCrossfading(@IdRes int imageViewResId, @DrawableRes int... drawableIds) {

    Drawable[] bitmapDrawables = new Drawable[drawableIds.length];

    for (int i = 0; i < drawableIds.length; i++) {
        // if you are using Vectors cross fade won't work unless you do this! - See my answer at https://stackoverflow.com/a/54583929/114549
        // bitmapDrawables[i] = getBitmapDrawableFromVectorDrawable(this, drawableIds[i]);
        bitmapDrawables[i] = ContextCompat.getDrawable(this, drawableIds[i]);
    }

    final ImageView imageView = findViewById(imageViewResId);

    handler.postDelayed(new Runnable() {
        int index = 0;
        @Override
        public void run() {

            TransitionDrawable td = new TransitionDrawable(new Drawable[]{
                    bitmapDrawables[index % bitmapDrawables.length],
                    bitmapDrawables[++index % bitmapDrawables.length]
            });
            td.setCrossFadeEnabled(true);
            imageView.setImageDrawable(td);

            td.startTransition(500); // transitionDurationMillis
            handler.postDelayed(this, 3000);
        }
    }, 3000);

}

暂停时应清理处理程序

handler.removeCallbacksAndMessages(null);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接