シンプルなゲームを作成するために、次のようなビットマップでキャンバスを描くテンプレートを使用しました。
private void doDraw(Canvas canvas) {
for (int i=0;i<8;i++)
for (int j=0;j<9;j++)
for (int k=0;k<7;k++) {
canvas.drawBitmap(mBits[allBits[i][j][k]], i*50 -k*7, j*50 -k*7, null); } }
(キャンバスは「run()」で定義されます/ SurfaceViewはGameThreadに存在します。)
最初の質問は、新しいレイアウトのwholeキャンバスをクリア(または再描画)するにはどうすればよいですか?
次に、画面の一部だけを更新するにはどうすればよいですか?
// This is the routine that calls "doDraw":
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
if (mMode == STATE_RUNNING)
updateGame();
doDraw(c); }
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c); } } } }
新しいレイアウトの全キャンバスをクリア(または再描画)するにはどうすればよいですか(=ゲームで試してください)?
Canvas.drawColor(Color.BLACK)
、またはCanvas
でクリアしたい色を呼び出すだけです。
そして:画面の一部だけを更新するにはどうすればよいですか?
Android OSは画面の更新時にすべてのピクセルを再描画するため、「画面の一部」を更新するだけの方法はありません。しかし、Canvas
の古い図面をクリアしていない場合、古い図面はまだ表面にあり、それはおそらく画面の「一部だけを更新する」方法の1つです。
したがって、「画面の一部を更新する」場合は、Canvas.drawColor()
メソッドを呼び出さないようにします。
PorterDuffのクリアモードで透明色を描画すると、私が望んでいたもののトリックができます。
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
これをグーグルグループで見つけて、これは私のために働いた..
Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, clearPaint);
これにより、設定されたビットマップを維持しながら、図面の長方形などが削除されます。
私は@mobistryの答えを試しました:
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
しかし、私にはうまくいきませんでした。
私にとっての解決策は次のとおりです。
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
たぶん同じ問題を抱えている人もいます。
pathクラスのresetメソッドを使用します
Path.reset();
mBitmap.eraseColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
以下のコードをSurfaceView拡張クラスコンストラクターに貼り付けてください。
コンストラクターコーディング
SurfaceHolder holder = getHolder();
holder.addCallback(this);
SurfaceView sur = (SurfaceView)findViewById(R.id.surfaceview);
sur.setZOrderOnTop(true); // necessary
holder = sur.getHolder();
holder.setFormat(PixelFormat.TRANSPARENT);
xMLコーディング
<com.welcome.panelview.PanelViewWelcomeScreen
Android:id="@+id/one"
Android:layout_width="600px"
Android:layout_height="312px"
Android:layout_gravity="center"
Android:layout_marginTop="10px"
Android:background="@drawable/welcome" />
上記のコードを試してください...
私にとってCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
または同様の呼び出しは、画面に触れた後にのみ機能します。 SO上記のコード行を呼び出しますが、画面に触れると画面がクリアされます。だから私のために働いたのは、ビューを初期化するために作成時に呼び出されるinvalidate()
に続いてinit()
を呼び出すことでした。
private void init() {
setFocusable(true);
setFocusableInTouchMode(true);
setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mCanvas = new Canvas();
mPaths = new LinkedList<>();
addNewPath();
}
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
以下は、各フレームでCanvasのすべてのピクセルを常に再描画する必要があることを示す最小限の例のコードです。
このアクティビティは、前に画面をクリアせずに、SurfaceViewに新しいビットマップを毎秒描画します。テストすると、ビットマップが常に同じバッファーに書き込まれるわけではなく、画面が2つのバッファー間で交互に表示されることがわかります。
電話(Nexus S、Android 2.3.3)およびエミュレーター(Android 2.2)でテストしました。
public class TestCanvas extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new TestView(this));
}
}
class TestView extends SurfaceView implements SurfaceHolder.Callback {
private TestThread mThread;
private int mWidth;
private int mHeight;
private Bitmap mBitmap;
private SurfaceHolder mSurfaceHolder;
public TestView(Context context) {
super(context);
mThread = new TestThread();
mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
mWidth = width;
mHeight = height;
mThread.start();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {/* Do nothing */}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread != null && mThread.isAlive())
mThread.interrupt();
}
class TestThread extends Thread {
@Override
public void run() {
while (!isInterrupted()) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
c.drawBitmap(mBitmap, (int) (Math.random() * mWidth), (int) (Math.random() * mHeight), null);
}
} finally {
if (c != null)
mSurfaceHolder.unlockCanvasAndPost(c);
}
try {
sleep(1000);
} catch (InterruptedException e) {
interrupt();
}
}
}
}
}
Invalidate()を呼び出すことを忘れないでください。
canvas.drawColor(backgroundColor);
invalidate();
path.reset();
次のアプローチを使用すると、キャンバス全体またはその一部のみをクリアできます。
PorterDuff.Mode.CLEARはハードウェアアクセラレーションでは動作しないため、ハードウェアアクセラレーションを無効にすることを忘れないでください。onDraw
メソッドをオーバーライドするため、最後にsetWillNotDraw(false)
を呼び出します。
//view's constructor
setWillNotDraw(false);
setLayerType(LAYER_TYPE_HARDWARE, null);
//view's onDraw
Paint TransparentPaint = new Paint();
TransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, TransparentPaint);