カラーバンディングは、さまざまなソリューションが提供されて以前に何度も議論されてきた問題の古い栗であることを認識しています(基本的に、全体で32ビットを使用するか、ディザリングを使用します)。実際、それほど前のことではありませんが、私はこれに関して自分自身のSOの質問をし、その後答えました。当時、私はその質問への回答に入れた解決策(これはに適用setFormat(PixelFormat.RGBA_8888)
され、の場合Window
もに適用される)が私のアプリケーションの問題を完全に解決したと思いました。少なくともこのソリューションは、当時私が開発していたデバイス(おそらくAndroid 2.2)でグラデーションを非常に見栄えよくしました。Holder
SurfaceView
現在、HTC One X(Android 4.0)とAsus Nexus 7(Android 4.1)を使用して開発しています。私がやろうとしたのは、の領域全体にグレーのグラデーションを適用することでしたSurfaceView
。包含Window
とHolder
が32ビットカラー用に構成されていることを確認したと思われますが、ひどいバンディングアーティファクトが発生します。実際、Nexus 7では、アーティファクトが動き回るのが見えます。これSurfaceView
は、もちろん継続的に描画しているものだけでなくView
、テスト目的でまったく同じグラデーションを描画するために一緒に追加した通常の場合にも発生します。もちろん、これらのアーティファクトが存在し、動き回っているように見える方法は、絶対にひどいように見えます。実際には、信号の弱いアナログTVを見るようなものです。両方View
まったく同じアーティファクトをSurfaceView
示し、一緒に動き回ります。
私の意図は、全体で32ビットを使用することであり、ディザリングは使用しないことです。私は、Window
Android4.0よりずっと前にデフォルトで32ビットだったという印象を受けています。に適用することRGBA_8888
で、SurfaceView
すべてが32ビットであると予想していたため、アーティファクトを回避できました。
RGBA_8888
SOについては、4.0/4.1プラットフォームではもはや効果がないように思われるという質問が他にもいくつかあることに注意してください。
これは私のNexus7のスクリーンショットView
で、上部とSurfaceView
下部に法線があり、どちらも同じグラデーションをに適用していCanvas
ます。もちろん、ディスプレイを見たときのようにアーティファクトは表示されないため、この画面グラブを表示することはおそらくかなり無意味です。ただし、ネクサスの画面ではバンディングが実際にひどく見えることを強調したいと思います。編集:実際、スクリーンショットにはアーティファクトがまったく表示されていません。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) {
}
}
}
GooglePlayからDisplayTesterというアプリケーションをインストールしました。このアプリケーションを使用して、画面上にテストグラデーションを作成できます。グラデーションは完璧には見えませんが、私が達成できたものよりも少し良く見えます。それは、バンディングを防ぐために私ができるさらなる対策があるかどうか疑問に思います。
もう1つ注意すべき点は、DisplayTesterアプリケーションがNexusの画面が32ビットであることを報告していることです。
参考までに、ハードウェアアクセラレーションを明示的に有効にしています。私のSDKレベルは次のとおりです。
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15"></uses-sdk>
もう1つ気付いたのはActivity
、Holoの機能であると私が理解している、のデフォルトのグラデーション背景も非常に縞模様になっていることです。これもスクリーンショットにはまったく表示されません。また、Nexus 7では、2つのバンディングの動きに共感して、背景のバンディングが一時的に動き回っていることにも気づきましたViews
。Activity
デフォルトの「空」で完全に新しいAndroidプロジェクトを作成するとActivity
、NexusとHTC One Xの両方で厄介な縞模様のグラデーションの背景が表示されます。これは正常ですか?Activity
この黒/紫のグラデーションのデフォルトの背景は、ハードウェアアクセラレーションが有効になっている場合に必要なものであることを理解しています。ええと、ハードウェアアクセラレーションが有効になっているかどうかに関係なく、同じ厄介な縞模様が表示されますActivity
背景のグラデーション。これは、ターゲットSDKが15である私の空のテストプロジェクトでも発生します。明確にするために、ハードウェアアクセラレーションを有効または無効にする方法は、明示的にとを使用android:hardwareAccelerated="true"
してandroid:hardwareAccelerated="false"
います。
ホロの黒/紫のグラデーションの背景についての私の観察Activity
が私の主な質問と関係があるかどうかはわかりませんが、それは奇妙なことに関連しているようです。また、ハードウェアアクセラレーションがオンになっているかどうかに関係なく、品質が低く(つまり、縞模様になっている)、同じように見えるのも奇妙です。したがって、2番目の質問は次のようになります。Activity
デフォルトのHoloグラデーションの背景があり、ハードウェアアクセラレーションが明示的に有効にされてから無効になっている場合、このグラデーションの背景は(a)存在し、(b)完全に滑らかに見える必要がありますか?これは別の質問で質問しますが、繰り返しになりますが、関連しているようです。
要約すると、私が抱えている基本的な問題は、グラデーションの背景をSurfaceView
単純に適用することはできないということです。私のNexus 7では、それが問題であるのはバンディングだけではありません。それ); 実際には、各ドローでバンディングがランダムであるという事実があります。これは、SurfaceView
絶えず再描画されるaが、移動するぼやけた背景を持つことになることを意味します。