Untuk membuat game sederhana, saya menggunakan template yang menggambar kanvas dengan bitmap seperti ini:
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); } }
(Kanvas didefinisikan dalam "run ()" / SurfaceView ada di GameThread.)
Pertanyaan pertama saya adalah bagaimana cara menghapus (atau menggambar ulang) seluruh kanvas untuk tata letak baru?
Kedua, bagaimana cara memperbarui hanya sebagian dari layar?
// 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); } } } }
sumber
mSurfaceHolder.unlockCanvasAndPost(c)
dan kemudianc = mSurfaceHolder.lockCanvas(null)
, maka yang baruc
tidak berisi hal yang sama seperti sebelumnyac
. Anda tidak dapat memperbarui hanya sebagian dari SurfaceView, yang menurut saya diminta OP.Canvas
menyimpan gambar lama.Menggambar warna transparan dengan mode jelas PorterDuff melakukan trik untuk apa yang saya inginkan.
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
sumber
Bitmap#eraseColor(Color.TRANSPARENT)
, seperti dalam jawaban HeMac di bawah ini.Color.TRANSPARENT
itu tidak perlu.PorterDuff.Mode.CLEAR
benar-benar cukup untukARGB_8888
bitmap yang berarti menyetel alfa dan warna ke [0, 0]. Cara lain adalah dengan menggunakanColor.TRANSPARENT
denganPorterDuff.Mode.SRC
.Menemukan ini di grup google dan ini berhasil untuk saya ..
Paint clearPaint = new Paint(); clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawRect(0, 0, width, height, clearPaint);
Ini menghapus gambar persegi panjang, dll. Sambil tetap menyetel bitmap ..
sumber
menggunakan metode reset kelas Path
Path.reset();
sumber
Saya mencoba jawaban @mobistry:
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
Tapi itu tidak berhasil untukku.
Solusinya, bagi saya, adalah:
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
Mungkin seseorang memiliki masalah yang sama.
sumber
mBitmap.eraseColor(Color.TRANSPARENT); canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
sumber
silakan tempel kode di bawah ini pada surfaceview memperpanjang konstruktor kelas .............
pengkodean konstruktor
SurfaceHolder holder = getHolder(); holder.addCallback(this); SurfaceView sur = (SurfaceView)findViewById(R.id.surfaceview); sur.setZOrderOnTop(true); // necessary holder = sur.getHolder(); holder.setFormat(PixelFormat.TRANSPARENT);
pengkodean 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" />
coba kode di atas ...
sumber
Berikut adalah kode contoh minimal yang menunjukkan bahwa Anda harus selalu menggambar ulang setiap piksel Canvas di setiap frame.
Aktivitas ini menggambar Bitmap baru setiap detik di SurfaceView, tanpa membersihkan layar sebelumnya. Jika Anda mengujinya, Anda akan melihat bahwa bitmap tidak selalu ditulis ke buffer yang sama, dan layar akan bergantian di antara kedua buffer tersebut.
Saya mengujinya di ponsel saya (Nexus S, Android 2.3.3), dan di emulator (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(); } } } } }
sumber
SurfaceHolder.Callback
, bukan hanyaCallback
.Canvas
jika kita ingin menggambar ulang seluruh layar sepenuhnya. Itu membuat pernyataan saya tentang "gambar sebelumnya" menjadi benar. ItuCanvas
menyimpan gambar sebelumnya.Canvas
pertahankan gambar sebelumnya. Tapi ini sama sekali tidak berguna, masalahnya adalah ketika Anda menggunakanlockCanvas()
Anda tidak tahu apa itu "gambar sebelumnya", dan tidak bisa berasumsi apa-apa tentang mereka. Mungkin jika ada dua aktivitas dengan SurfaceView dengan ukuran yang sama, keduanya akan menggunakan Canvas yang sama. Mungkin Anda mendapatkan sepotong RAM yang tidak diinisialisasi dengan byte acak di dalamnya. Mungkin selalu ada logo Google yang tertulis di Canvas. Anda tidak bisa tahu. Aplikasi apa pun yang tidak menggambar setiap piksel setelahnyalockCanvas(null)
rusak.Bagi saya menelepon
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
atau sesuatu yang serupa hanya akan berfungsi setelah saya menyentuh layar. JADI saya akan memanggil baris kode di atas tetapi layar hanya akan bersih setelah saya menyentuh layar. Jadi yang berhasil bagi saya adalah memanggil yanginvalidate()
diikuti olehinit()
yang dipanggil pada saat pembuatan untuk menginisialisasi tampilan.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(); }
sumber
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
sumber
Menghapus pada Canvas di java android sama seperti menghapus HTML Canvas melalui javascript dengan globalCompositeOperation. Logikanya serupa.
U akan memilih logika DST_OUT (Tujuan Keluar).
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
Catatan: DST_OUT lebih berguna karena dapat menghapus 50% jika warna cat memiliki 50% alpha. Jadi, untuk benar-benar menjadi transparan, alpha warna harus 100%. Disarankan menggunakan paint.setColor (Color.WHITE). Dan pastikan bahwa format gambar kanvas adalah RGBA_8888.
Setelah terhapus, kembali ke gambar normal dengan SRC_OVER (Source Over).
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
Perbarui tampilan area kecil secara harfiah perlu mengakses perangkat keras grafis, dan mungkin tidak didukung.
Yang paling mendekati untuk performa tertinggi adalah menggunakan lapisan multi gambar.
sumber
Jangan lupa untuk memanggil invalidate ();
canvas.drawColor(backgroundColor); invalidate(); path.reset();
sumber
invalidate
setelah menggambar sesuatu?Coba hapus tampilan di onPause () dari suatu aktivitas dan tambahkan onRestart ()
LayoutYouAddedYourView.addView (YourCustomView); LayoutYouAddedYourView.removeView (YourCustomView);
Saat Anda menambahkan tampilan, metode onDraw () akan dipanggil.
YourCustomView, adalah kelas yang memperluas kelas View.
sumber
Dalam kasus saya, saya menggambar kanvas saya menjadi linearlayout. Untuk membersihkan dan menggambar ulang lagi:
LinearLayout linearLayout = findViewById(R.id.myCanvas); linearLayout.removeAllViews();
dan kemudian, saya memanggil kelas dengan nilai baru:
Lienzo fondo = new Lienzo(this,items); linearLayout.addView(fondo);
Ini adalah kelas Lienzo:
class Lienzo extends View { Paint paint; RectF contenedor; Path path; ArrayList<Items>elementos; public Lienzo(Context context,ArrayList<Items> elementos) { super(context); this.elementos=elementos; init(); } private void init() { path=new Path(); paint = new Paint(); contenedor = new RectF(); paint.setStyle(Paint.Style.FILL); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); contenedor.left = oneValue; contenedor.top = anotherValue; contenedor.right = anotherValue; contenedor.bottom = anotherValue; float angulo = -90; //starts drawing at 12 o'clock //total= sum of all element values for (int i=0;i<elementos.size();i++){ if (elementos.get(i).angulo!=0 && elementos.get(i).visible){ paint.setColor(elementos.get(i).backColor); canvas.drawArc(contenedor,angulo,(float)(elementos.get(i).value*360)/total,true,paint); angulo+=(float)(elementos.get(i).value*360)/total; } } //for example } }
sumber
Dengan pendekatan berikut, Anda dapat menghapus seluruh kanvas atau hanya sebagian saja.
Harap jangan lupa untuk menonaktifkan akselerasi Perangkat Keras karena PorterDuff.Mode.CLEAR tidak berfungsi dengan akselerasi perangkat keras dan akhirnya memanggil
setWillNotDraw(false)
karena kami menggantionDraw
metode tersebut.//view's constructor setWillNotDraw(false); setLayerType(LAYER_TYPE_SOFTWARE, null); //view's onDraw Paint TransparentPaint = new Paint(); TransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawRect(0, 0, width, height, TransparentPaint);
sumber
LAYER_TYPE_HARDWARE
keLAYER_TYPE_SOFTWARE
Persyaratan pertama Anda, cara menghapus atau menggambar ulang seluruh kanvas - Jawaban - gunakan metode canvas.drawColor (color.Black) untuk membersihkan layar dengan warna hitam atau apa pun yang Anda tentukan.
Persyaratan kedua Anda, bagaimana memperbarui bagian layar - Jawab - misalnya jika Anda ingin menyimpan semua hal lain tidak berubah di layar tetapi di area kecil layar untuk menunjukkan bilangan bulat (katakanlah penghitung) yang meningkat setiap lima detik. kemudian gunakan metode canvas.drawrect untuk menggambar area kecil itu dengan menentukan kiri atas kanan bawah dan cat. kemudian hitung nilai penghitung Anda (menggunakan postdalayed selama 5 detik dll., Seperti Handler.postDelayed (Runnable_Object, 5000);), konversikan ke string teks, hitung koordinat x dan y dalam kotak kecil ini dan gunakan tampilan teks untuk menampilkan perubahan nilai counter.
sumber
Saya harus menggunakan kartu gambar terpisah untuk membersihkan kanvas (mengunci, menggambar, dan membuka kunci):
Canvas canvas = null; try { canvas = holder.lockCanvas(); if (canvas == null) { // exit drawing thread break; } canvas.drawColor(colorToClearFromCanvas, PorterDuff.Mode.CLEAR); } finally { if (canvas != null) { holder.unlockCanvasAndPost(canvas); } }
sumber
Telepon saja
canvas.drawColor (Color.TRANSPARENT)
sumber
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
. Kalau tidak salah, warna sebenarnya bisa apa saja (tidak harus TRANSPARAN) karenaPorterDuff.Mode.CLEAR
hanya akan menghapus klip yang sedang diputar (seperti melubangi kanvas).