在Android中,我如何平滑地将背景从一种颜色渐变到另一种颜色?(如何使用线程)

36

我已经断断续续地学习Android编程几周了,我正在尝试做一些看起来很简单的东西,但我认为我错过了什么。

我想要做的是让背景从白色平滑过渡到黑色。

我已经尝试了一些方法,但都没有成功。

我首先使用了一个for循环和LinearLayout的setBackgroundColor方法,一起从0到255改变R、G和B值。但它不起作用。

我可以进行单个设置更改,但当我循环时,只得到最后一个值。我认为发生的事情是UI在循环进行时被锁定,在循环结束时解锁。我已经尝试在循环中放置延迟(丑陋的嵌套循环延迟和Thread.sleep),但都无济于事。

有人能给我指点如何使其工作吗?我需要第二个线程来对颜色进行更改吗?我对线程有一个模糊的概念,虽然我从未使用过。

我的示例代码大致显示了我要做的事情:

main.xml是:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/screen"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>

我的 Java 代码为(0.01 的增量只是为了作为一个丑陋的延迟机制,以尝试缓慢地观察颜色变化):

package nz.co.et.bgfader;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;

public class bgfader extends Activity {

    LinearLayout screen;

/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        screen = (LinearLayout) findViewById(R.id.screen);
        for (int i = 0; i < 65535; i+=0.01) {
            screen.setBackgroundColor(0xff000000 + i);
        }
    }
}

非常感谢任何帮助。

谢谢!

Steve

6个回答

100

如果您感兴趣,我发现了一种改变背景颜色的方法--我认为使用动画比您目前拥有的更容易 :)

如果您使用的是API Level 11或以上版本,则可以在LinearLayout的背景颜色上使用ObjectAnimator。

 ObjectAnimator colorFade = ObjectAnimator.ofObject(screen, "backgroundColor", new ArgbEvaluator(), Color.argb(255,255,255,255), 0xff000000);
  colorFade.setDuration(7000);
  colorFade.start();

还有一点需要注意,必须使用32位int颜色代码。有关详细信息,请参见http://developer.android.com/reference/android/graphics/Color.html。您可以使用Color.argb、Color.rgb、我上面使用的十六进制值,或查看int颜色常量。


谢谢你的回复 - 我使用的是2.2版本,所以这个解决方案不会起作用...而且考虑到这是一个给我女儿用的小夜灯应用程序,她的平板电脑是基于2.2的,我需要坚持使用原始的线程选项...但我喜欢这种简单的方式,所以我可能会试试它。干杯 - Steve
真的很好知道。可惜只适用于3.0及以上版本。正在寻找类似于2.2 / 2.3+的解决方案。 - speedynomads

13
更好的回答是使用 ObjectAnimator
ObjectAnimator colorFade = ObjectAnimator.ofObject(view, "backgroundColor" /*view attribute name*/, new ArgbEvaluator(), mContext.getResources().getColor(R.color.colorMenuOverlay) /*from color*/, Color.WHITE /*to color*/);
                colorFade.setDuration(3500);
                colorFade.setStartDelay(200);
                colorFade.start();

12

在你的循环中,你设置的背景太快了,以至于UI无法(或将无法)安排显示的更新。是的,最好使用第二个线程来更新后台,否则你将阻塞UI线程。尝试以下:

LinearLayout screen;
Handler handler = new Handler();

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    screen = (LinearLayout) findViewById(R.id.screen);

    (new Thread(){
        @Override
        public void run(){
            for(int i=0; i<255; i++){
                handler.post(new Runnable(){
                    public void run(){
                        screen.setBackgroundColor(Color.argb(255, i, i, i));
                    }
                });
                // next will pause the thread for some time
                try{ sleep(10); }
                catch{ break; }
            }
        }
    }).start();
}

这是您的代码的线程化版本。


5
谢谢! :) 有了一些小改变,它就开始运作了。我不得不将其变为全局变量,因为否则无法在run方法内部访问它(或者我可以传递它)。我还必须调整try/catch,因为原来的代码对我而言无法编译。非常感谢,这让我疯狂了几天。现在它能工作,我将使用线程进行尝试,并看看是否能用这段代码制作出有趣的东西。 - Steve
3
这不是一种好的做法。你不能在后台线程更新UI。@Amy的建议是正确的。有一个叫做http://nineoldandroids.com/的项目,它实现了Android 3.0以前版本的ObjectAnimator。 - tofi9
如果我想使用seekbar值在TextView中实现从一种颜色渐变到另一种颜色,该怎么办? - Si8
如果每帧更新一次并使用delta时间变量来乘以结果,这将在某些设备上增加和减少速度。 - Oliver Dixon

3
如果有人正在寻找3.0之前的解决方案,Nine Old Androids可以让您在Android 1.0及以后的设备上使用动画API。http://nineoldandroids.com/

1

一些旧设备的另外几个解决方案:

TIMER

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final Timer myTimer = new Timer();
    final View myview = getWindow().getDecorView().findViewById(
            android.R.id.content);

    myTimer.schedule(new TimerTask() {
        int color = 0;
        @Override
        public void run() {
            // If you want to modify a view in your Activity
            runOnUiThread(new Runnable() {
                public void run() {
                    color++;
                    myview.setBackgroundColor(Color.argb(255, color, color,
                            color));
                    if (color == 255)
                        myTimer.cancel();
                }
            });
        }
    }, 1000, 20); // initial delay 1 second, interval 1 second

}

线程
    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    new Thread() {
        int color = 0;
        View myview = getWindow().getDecorView().findViewById(
                android.R.id.content);
        @Override
        public void run() {
            for (color = 0; color < 255; color++) {
                try {
                    sleep(20);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            myview.setBackgroundColor(Color.argb(255,
                                    color, color, color));
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}

0
private fun applyColorFade(fromColor: Int, toColor: Int) {
    ObjectAnimator.ofObject(
        toolbar, "backgroundColor", ArgbEvaluator(), 
        fromColor,
        toColor
    ).apply {
      duration = 2000
      startDelay = 200
      start()
    }
}

// 这是一个用于视图颜色渐变动画的可重复使用的方法


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