Чтобы сделать простую игру, я использовал шаблон, который рисует холст с такими растровыми изображениями:
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.)
Мой первый вопрос: как очистить (или перерисовать) весь холст для нового макета?
Во-вторых, как я могу обновить только часть экрана?
// 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); } } } }
источник
mSurfaceHolder.unlockCanvasAndPost(c)
а затемc = mSurfaceHolder.lockCanvas(null)
, то новоеc
не будет содержать того же, что и предыдущееc
. Вы не можете обновить только часть SurfaceView, о чем, я думаю, спрашивал OP.Canvas
хранит старые чертежи.Рисование прозрачным цветом в режиме очистки PorterDuff делает то, что я хотел.
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
источник
Bitmap#eraseColor(Color.TRANSPARENT)
, как в ответе HeMac ниже.Color.TRANSPARENT
это не нужно.PorterDuff.Mode.CLEAR
вполне достаточно дляARGB_8888
растрового изображения, что означает установку альфа и цвета на [0, 0]. Другой способ - использоватьColor.TRANSPARENT
сPorterDuff.Mode.SRC
.Нашел это в группах Google, и это сработало для меня ..
Paint clearPaint = new Paint(); clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawRect(0, 0, width, height, clearPaint);
Это удаляет прямоугольники чертежей и т. Д., Сохраняя при этом установленное растровое изображение.
источник
используйте метод сброса класса Path
Path.reset();
источник
Я попробовал ответ @mobistry:
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
Но у меня это не сработало.
Решение для меня было:
canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);
Может у кого-то такая же проблема.
источник
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" />
попробуйте код выше ...
источник
Вот код минимального примера, показывающий, что вам всегда нужно перерисовывать каждый пиксель холста в каждом кадре.
Это действие рисует новое растровое изображение каждую секунду в SurfaceView без предварительной очистки экрана. Если вы его протестируете, вы увидите, что растровое изображение не всегда записывается в один и тот же буфер, и экран будет попеременно переключаться между двумя буферами.
Я тестировал его на своем телефоне (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(); } } } } }
источник
SurfaceHolder.Callback
, а не просто такCallback
.Canvas
если мы хотим полностью перерисовать весь экран. Это делает мое утверждение о «предыдущих рисунках» верным.Canvas
Сохраняет предыдущие рисунки.Canvas
сохраняет предыдущие рисунки. Но это совершенно бесполезно, проблема в том, что при использованииlockCanvas()
вы не знаете, что это за «предыдущие рисунки», и не можете ничего предполагать о них. Возможно, если есть два действия с SurfaceView одинакового размера, они будут использовать один и тот же Canvas. Возможно, вы получите кусок неинициализированной оперативной памяти со случайными байтами в ней. Возможно, на холсте всегда есть логотип Google. Вы не можете знать. Любое приложение, которое не рисует каждый пиксель послеlockCanvas(null)
, ломается.Для меня звонок
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
или что-то подобное будет работать только после того, как я коснусь экрана. Итак, я бы назвал приведенную выше строку кода, но экран очистился бы только после того, как я коснулся экрана. Итак, что сработало для меня, так это вызов,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 в java android аналогично стиранию HTML Canvas через javascript с помощью globalCompositeOperation. Логика была похожей.
U выберет логику DST_OUT (Destination Out).
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
Примечание: DST_OUT более полезен, потому что он может стереть 50%, если цвет краски имеет 50% альфа. Итак, чтобы полностью очистить до прозрачности, альфа цвета должна быть 100%. Рекомендуется применить paint.setColor (Color.WHITE). И убедитесь, что формат изображения холста был RGBA_8888.
После стирания вернитесь к нормальному рисованию с помощью SRC_OVER (Source Over).
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
Обновление дисплея с небольшой площадью буквально потребует доступа к графическому оборудованию, а оно, возможно, не поддерживается.
Наиболее близким для максимальной производительности является использование слоя с несколькими изображениями.
источник
Не забудьте вызвать invalidate ();
canvas.drawColor(backgroundColor); invalidate(); path.reset();
источник
invalidate
после того, как что-то нарисовали?Попробуйте удалить представление в onPause () действия и добавить onRestart ()
LayoutYouAddedYourView.addView (YourCustomView); LayoutYouAddedYourView.removeView (YourCustomView);
В тот момент, когда вы добавите свое представление, будет вызван метод onDraw ().
YourCustomView - это класс, расширяющий класс View.
источник
В моем случае я рисую свой холст в формате linearlayout. Чтобы очистить и снова перерисовать:
LinearLayout linearLayout = findViewById(R.id.myCanvas); linearLayout.removeAllViews();
а затем я вызываю класс с новыми значениями:
Lienzo fondo = new Lienzo(this,items); linearLayout.addView(fondo);
Это класс Лиенцо:
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 } }
источник
С помощью следующего подхода вы можете очистить холст целиком или только его часть.
Пожалуйста, не забудьте отключить аппаратное ускорение, поскольку PorterDuff.Mode.CLEAR не работает с аппаратным ускорением и, наконец, вызывается,
setWillNotDraw(false)
потому что мы переопределяемonDraw
метод.//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);
источник
LAYER_TYPE_HARDWARE
наLAYER_TYPE_SOFTWARE
Ваше первое требование, как очистить или перерисовать весь холст - Ответ - используйте метод canvas.drawColor (color.Black) для очистки экрана черным цветом или любым другим цветом, который вы укажете.
Ваше второе требование, как обновить часть экрана - Ответ - например, если вы хотите, чтобы все остальные вещи на экране оставались неизменными, но в небольшой области экрана отображалось целое число (например, счетчик), которое увеличивается каждые пять секунд. затем используйте метод canvas.drawrect, чтобы нарисовать эту небольшую область, указав левый верхний правый нижний и рисуя. затем вычислите значение своего счетчика (используя postdalayed в течение 5 секунд и т. д., как Handler.postDelayed (Runnable_Object, 5000);), преобразуйте его в текстовую строку, вычислите координаты x и y в этом маленьком прямоугольнике и используйте текстовое представление для отображения изменяющихся значение счетчика.
источник
Мне пришлось использовать отдельный проход рисования, чтобы очистить холст (заблокировать, нарисовать и разблокировать):
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); } }
источник
Просто позвони
canvas.drawColor (Color.TRANSPARENT)
источник
Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
. Если я не ошибаюсь, цвет на самом деле может быть любым (не обязательно ПРОЗРАЧНЫМ), потому чтоPorterDuff.Mode.CLEAR
он просто очистит текущий клип (например, пробив дыру в холсте).