【发布时间】:2012-08-13 05:07:46
【问题描述】:
我知道色带是一个老问题,之前已经讨论过很多次,并提供了各种解决方案(基本上归结为始终使用 32 位或使用抖动)。事实上不久前我asked and subsequently answered my own SO question对此。那时,我认为我在该问题的答案中提出的解决方案(将setFormat(PixelFormat.RGBA_8888) 应用于Window 以及在SurfaceView 的情况下应用于Holder)已经解决了问题我的申请很好。至少该解决方案使渐变在我当时开发的设备上看起来非常漂亮(很可能是 Android 2.2)。
我现在正在使用 HTC One X (Android 4.0) 和 Asus Nexus 7 (Android 4.1) 进行开发。我试图做的是对SurfaceView 的整个区域应用灰色渐变。尽管我应该确保包含 Window 和 Holder 配置为 32 位颜色,但我得到了可怕的条带伪影。事实上,在 Nexus 7 上,我什至可以看到工件在移动。这不仅发生在SurfaceView 上,它当然是连续绘制的,而且也发生在一个普通的View 上,我在旁边添加了为了测试目的绘制完全相同的渐变,它本来会绘制一次。这些伪影存在并且似乎四处移动的方式当然看起来非常糟糕,这实际上就像观看信号不佳的模拟电视。 View 和 SurfaceView 都展示了完全相同的工件,它们一起移动。
我的意图是始终使用 32 位,而不是使用抖动。我的印象是,早在 Android 4.0 之前,Window 就默认为 32 位。通过在SurfaceView 中应用RGBA_8888,我原以为一切都是32 位的,从而避免了任何伪影。
我确实注意到关于 SO 的其他一些问题,人们观察到 RGBA_8888 在 4.0 / 4.1 平台上似乎不再有效。
这是我的 Nexus 7 的屏幕截图,顶部是普通的 View,下方是 SurfaceView,两者都对 Canvas 应用相同的渐变。当然,它不会像查看显示器时那样显示伪影,因此显示此屏幕抓取可能毫无意义。我想强调的是,在 Nexus 的屏幕上,条带确实看起来很糟糕。 编辑:事实上,屏幕截图确实没有显示工件。我在 Nexus 7 上看到的伪影不是统一的条带;它本质上看起来是随机的。
用于创建上述内容的测试Activity:
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.os.Bundle;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.widget.LinearLayout;
public class GradientTest extends Activity {
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
getWindow().setFormat(PixelFormat.RGBA_8888);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(getWindow().getAttributes());
lp.format = PixelFormat.RGBA_8888;
getWindow().setAttributes(lp);
LinearLayout ll = new LinearLayout(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500,500);
params.setMargins(20, 0, 0, 0);
ll.addView(new GradientView(this), params);
ll.addView(new GradientSurfaceView(this), params);
ll.setOrientation(LinearLayout.VERTICAL);
setContentView(ll);
}
public class GradientView extends View {
public GradientView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(false);
paint.setFilterBitmap(false);
paint.setDither(false);
Shader shader = new LinearGradient(
0,
0,
0,
500,
//new int[]{0xffafafaf, 0xff414141},
new int[]{0xff333333, 0xff555555},
null,
Shader.TileMode.CLAMP
);
paint.setShader(shader);
canvas.drawRect(0,0,500,500, paint);
}
}
public class GradientSurfaceView extends SurfaceView implements Callback {
public GradientSurfaceView(Context context) {
super(context);
getHolder().setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
Paint paint;
private GraphThread thread;
@Override
public void surfaceCreated(SurfaceHolder holder) {
holder.setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(false);
paint.setFilterBitmap(false);
paint.setDither(false);
Shader shader = new LinearGradient(
0,
0,
0,
500,
//new int[]{0xffafafaf, 0xff414141},
new int[]{0xff333333, 0xff555555},
null,
Shader.TileMode.CLAMP
);
paint.setShader(shader);
thread = new GraphThread(holder, new Handler() );
thread.setName("GradientSurfaceView_thread");
thread.start();
}
class GraphThread extends Thread {
/** Handle to the surface manager object we interact with */
private SurfaceHolder mSurfaceHolder;
public GraphThread(SurfaceHolder holder, Handler handler) {
mSurfaceHolder = holder;
holder.setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients
}
@Override
public void run() {
Canvas c = null;
while (true) {
try {
c = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
if (c != null){
c.drawRect(0,0,500,500, paint);
}
}
}
finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
}
我从 Google Play 安装了一个名为 Display Tester 的应用程序。此应用程序可用于在屏幕上创建测试梯度。虽然它的渐变看起来并不完美,但它们似乎比我能够实现的要好一些,这让我想知道是否可以采取进一步措施来防止条带化。
我注意到的另一件事是 Display Tester 应用程序报告我的 Nexus 的屏幕是 32 位的。
关于信息,我明确启用硬件加速。我的 SDK 级别是:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15"></uses-sdk>
我注意到的另一件事是Activity 的默认渐变背景,据我所知,这是 Holo 的一个功能,它也是非常带状的。这也根本没有显示在屏幕截图中。而且,我还注意到我的 Nexus 7 上的背景条带短暂移动,这与我的两个 Views 中的条带移动表示同情。如果我使用默认的“空”Activity 创建一个全新的 Android 项目,Activity 在我的 Nexus 和 HTC One X 上都会显示令人讨厌的带状渐变背景。这正常吗?我知道这个黑色/紫色渐变默认背景是Activity 在启用硬件加速时应该拥有的。好吧,无论是否启用了硬件加速,我都会看到同样令人讨厌的带状Activity 背景渐变。这甚至发生在我的空测试项目中,其目标 SDK 为 15。澄清一下,我启用或禁用硬件加速的方式是显式使用 android:hardwareAccelerated="true" 和 android:hardwareAccelerated="false"。
我不确定我对 Holo black/purple Activity 渐变背景的观察是否与我的主要问题有关,但它似乎确实相关。奇怪的是它看起来质量如此差(即带状)并且无论是否打开硬件加速看起来都一样。所以,第二个问题是:当您有一个具有默认 Holo 渐变背景的Activity 时,并且对于硬件加速被明确启用然后禁用的每种情况,这个渐变背景 (a) 是否存在并且 (b) 看起来完美光滑?我会在一个单独的问题中问这个问题,但同样,它似乎是相关的。
所以,总而言之:我遇到的基本问题是,在我的 Nexus 7 上似乎根本无法将渐变背景应用于 SurfaceView。这不仅仅是条带问题(如果只是这样,我可以很高兴地忍受);实际上,每次抽签时,条带本质上都是随机的。这意味着不断重绘的SurfaceView 最终会有一个移动的、模糊的背景。
【问题讨论】:
-
我在同一个问题上苦苦挣扎,而您其他问题的解决方案为我解决了这个问题。我在三星 Galaxy S2 上使用 Android 4.0
-
Trevor 当我应用 getHolder().setFormat(PixelFormat.RGBA_8888); 时,我有一个 Nexus7 (2013);正如您提到的问题中所述,它解决了问题,并且条带消失了。
标签: android colors surfaceview bit-depth