Рисование на холсте - PorterDuff.Mode.CLEAR рисует черным цветом! Почему?
Я пытаюсь создать настраиваемый вид, который 9X_android-ui работает просто: есть растровое изображение, которое 9X_android-mobile отображается по дуге - от 0 до 360 градусов. Градусы 9X_android-application меняются с некоторым FPS.
Итак, я создал 9X_android-application собственный вид с переопределенным методом 9X_porter-duff onDraw()
:
@Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); arcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); canvas.drawArc(arcRectF, -90, currentAngleSweep, true, arcPaint); arcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, circleSourceRect, circleDestRect, arcPaint); }
arcPaint
инициализируется следующим образом:
arcPaint = new Paint(); arcPaint.setAntiAlias(true); arcPaint.setColor(Color.RED); // Color doesn't matter
Теперь 9X_android-sdk все отлично прорисовывается, но ... фон 9X_android-application ЧЕРНЫЙ во всем просмотре.
Если я установлю 9X_android-api canvas.drawColor(..., PorterDuff.Mode.DST)
и опущу canvas.drawBitmap()
- дуга будет правильно нарисована 9X_android-framework на прозрачном фоне.
У меня вопрос - как настроить 9X_drawing режимы PorterDuff
, чтобы он работал с прозрачностью?
Конечно, bitmap
- это 9X_android-sdk 32-битный PNG с альфа-каналом.
- вы нашли решение? Я на полпути, но когда я пытаюсь сохранить растровое изображение, к ...
Ответ #1
Ответ на вопрос: Рисование на холсте - PorterDuff.Mode.CLEAR рисует черным цветом! Почему?
PorterDuff.Mode.CLEAR
не работает с аппаратным ускорением. Просто 9X_android-mobile установите
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
У меня отлично работает.
- У меня была эта проблема с черным цветом последние два дня. Спасибо, чувак. работает как шарм :)<p><s ...
Ответ #2
Ответ на вопрос: Рисование на холсте - PorterDuff.Mode.CLEAR рисует черным цветом! Почему?
Используйте этот оператор во время инициализации 9X_android-api представления
setLayerType(LAYER_TYPE_HARDWARE, null);
Ответ #3
Ответ на вопрос: Рисование на холсте - PorterDuff.Mode.CLEAR рисует черным цветом! Почему?
В вашем коде все в порядке, кроме одного: вы 9X_android-api получаете черный фон, потому что ваше окно 9X_android-api непрозрачно. Чтобы добиться прозрачного 9X_android-mobile результата, вы должны рисовать на другом 9X_drawing растровом изображении. В вашем методе onDraw 9X_android-framework создайте новое растровое изображение и сделайте 9X_android-framework на нем весь персонал. После этого нарисуйте 9X_android-device это растровое изображение на своем холсте.
Подробную 9X_canvas информацию и образец кода см. в this my answer:
- Теперь представьте, что вы создаете для каждого onDraw() новый Bitmap и рисуете на нем. Похоже, убивает приложение. Наконец грустно с ...
Ответ #4
Ответ на вопрос: Рисование на холсте - PorterDuff.Mode.CLEAR рисует черным цветом! Почему?
для устранения нежелательного эффекта PorterDuff
сначала 9X_android-framework используйте самый простой метод, например, проблему 9X_android-application OP, достаточно Path.arcTo(*, *, *, *, false)
- обратите внимание, что 9X_android-ui это arcTo
, а не addArc
, а false
означает no forceMoveTo
перед добавлением 9X_android-device дуги - нет необходимости PorterDuff
.
Path arcPath = new Path(); @Override protected void onDraw(Canvas canvas) { arcPath.rewind(); arcPath.moveTo(arcRectF.centerX, arcRectF.centerY); arcPath.arcTo(arcRectF, -90, currentAngleSweep, false); arcPath.close(); canvas.clipPath(arcPath, Region.Op.DIFFERENCE); canvas.drawBitmap(bitmap, circleSourceRect, circleDestRect, arcPaint); }
если вам действительно 9X_android нужен PorterDuff, в основном для сложного 9X_android-framework морфинга цветов, например для смешивания 9X_android-ui градиентов, не рисуйте цвет, форму или растровое 9X_android-device изображение с эффектом фильтрации PorterDuff 9X_porter-duff непосредственно на холсте по умолчанию, представленном 9X_android-sdk в onDraw(Canvas)
, используйте растровое изображение буферизации 9X_porter-duff / назначения [ s] с альфа-каналом - и setHasAlpha(true)
- для 9X_canvas сохранения результата фильтрации PorterDuff, наконец, нарисуйте 9X_android-device растровое изображение на холсте по умолчанию 9X_android-application без применения какой-либо фильтрации, кроме 9X_canvas изменения матрицы.
вот рабочий пример создания 9X_android-ui круглого изображения с размытой рамкой:
import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.widget.ImageView; /** * Created by zdave on 6/22/17. */ public class BlurredCircleImageViewShader extends ImageView { private Canvas mCanvas; private Paint mPaint; private Matrix matrix; private static final float GRADIENT_RADIUS = 600f; //any value you like, but should be big enough for better resolution. private Shader gradientShader; private Bitmap bitmapGradient; private Bitmap bitmapDest; private Canvas canvasDest; public BlurredCircleImageViewShader(Context context) { this(context, null); } public BlurredCircleImageViewShader(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public BlurredCircleImageViewShader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); matrix = new Matrix(); int[] colors = new int[]{Color.BLACK, Color.BLACK, Color.TRANSPARENT}; float[] colorStops = new float[]{0f, 0.5f, 1f}; gradientShader = new RadialGradient(GRADIENT_RADIUS, GRADIENT_RADIUS, GRADIENT_RADIUS, colors, colorStops, Shader.TileMode.CLAMP); mPaint.setShader(gradientShader); bitmapGradient = Bitmap.createBitmap((int)(GRADIENT_RADIUS * 2), (int)(GRADIENT_RADIUS * 2), Bitmap.Config.ARGB_8888); bitmapDest = bitmapGradient.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(bitmapGradient); canvas.drawRect(0, 0, GRADIENT_RADIUS * 2, GRADIENT_RADIUS * 2, mPaint); canvasDest = new Canvas(bitmapDest); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); setMeasuredDimension(width, width); } @Override protected void onDraw(Canvas canvas){ /*uncomment each of them to show the effect, the first and the third one worked, the second show the same problem as OP's*/ //drawWithLayers(canvas); //unrecommended. //drawWithBitmap(canvas); //this shows transparent as black drawWithBitmapS(canvas); //recommended. } @SuppressLint("WrongCall") private void drawWithLayers(Canvas canvas){ mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); float width = canvas.getWidth(); float hWidth = width / 2; //both saveLayerAlpha saveLayer worked here, and if without either of them, //the transparent area will be black. //int count = canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 255, Canvas.ALL_SAVE_FLAG); int count = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG); super.onDraw(canvas); float scale = hWidth/GRADIENT_RADIUS; matrix.setTranslate(hWidth - GRADIENT_RADIUS, hWidth - GRADIENT_RADIUS); matrix.postScale(scale, scale, hWidth, hWidth); gradientShader.setLocalMatrix(matrix); canvas.drawRect(0, 0, width, width, mPaint); canvas.restoreToCount(count); } @SuppressLint("WrongCall") private void drawWithBitmap(Canvas canvas){ super.onDraw(canvas); float scale = canvas.getWidth() / (GRADIENT_RADIUS * 2); matrix.setScale(scale, scale); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawBitmap(bitmapGradient, matrix, mPaint); //transparent area is still black. } @SuppressLint("WrongCall") private void drawWithBitmapS(Canvas canvas){ float scale = canvas.getWidth() / (GRADIENT_RADIUS * 2); int count = canvasDest.save(); canvasDest.scale(1/scale, 1/scale); //tell super to draw in 1/scale. super.onDraw(canvasDest); canvasDest.restoreToCount(count); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvasDest.drawBitmap(bitmapGradient, 0, 0, mPaint); matrix.setScale(scale, scale); //to scale bitmapDest to canvas. canvas.drawBitmap(bitmapDest, matrix, null); } }
некоторые 9X_android-mobile примечания: 1, это представление расширяет 9X_android-device ImageView
, а не View
, есть некоторые отличия.
2, почему 9X_android drawWithLayers
- saveLayer
или saveLayerAlpha
- не рекомендуется: a, они не уверены, иногда 9X_android не работают правильно (отображаются прозрачными 9X_android-mobile как черный), особенно для View
, у которых onDraw(Canvas)
пуст 9X_android , в то время как ImageView.onDraw(Canvas)
использовал Drawable
для рисования; б, они 9X_canvas дорогие, они выделяют off-screen bitmap
для хранения временных 9X_android-ui результатов рисования, и нет четких указаний 9X_canvas на какой-либо механизм повторного использования 9X_drawing ресурсов.
3, с использованием вашего собственного 9X_android-application растрового изображения [s], лучше подходит 9X_drawing для индивидуальной утилизации ресурсов.
Некоторые 9X_android-device люди говорят, что невозможно использовать 9X_android-ui PorterDuff без распределения битовых карт 9X_drawing на каждом рисунке, потому что ширина и высота 9X_android-framework растрового изображения не могут быть определены 9X_drawing перед рисованием / компоновкой / измерением.
вы 9X_drawing МОЖЕТЕ использовать растровые изображения 9X_android-sdk буферизации для рисования PorterDuff:
сначала 9X_android-application выделите достаточно большие растровые изображения.
затем 9X_canvas нарисуйте растровое изображение [ы] с некоторой 9X_android-sdk матрицей.
и нарисуйте растровое изображение 9X_drawing [s] в целевое растровое изображение с некоторой 9X_android-device матрицей.
наконец, нарисуйте целевое растровое 9X_canvas изображение на холсте с некоторой матрицей.
некоторые 9X_android-application люди рекомендуют setLayerType (View.LAYER_TYPE_SOFTWARE, null), что 9X_android-framework для меня не вариант, потому что он вызовет 9X_drawing onDraw (Canvas) в цикле.
result image source image
Ответ #5
Ответ на вопрос: Рисование на холсте - PorterDuff.Mode.CLEAR рисует черным цветом! Почему?
В Jetpack Compose вы можете использовать blendMode
:
Canvas(modifier = Modifier.fillMaxSize()) { drawIntoCanvas { it.saveLayer(Rect(Offset.Zero, size), Paint()) } drawRect(color = Color.Blue, size = size) val clearSize = Size(200.dp.toPx(), 300.dp.toPx()) drawRect( color = Color.Transparent, topLeft = Offset((size.width - clearSize.width) / 2, (size.height - clearSize.height) / 2), size = clearSize, blendMode = BlendMode.Clear ) }
9X_drawing
-
5
-
2
-
3
-
2
-
1
-
5
-
6
-
4
-
2
-
3
-
6
-
6
-
6
-
1
-
4
-
3
-
2
-
2
-
5
-
3
-
5
-
2
-
11
-
6
-
13
-
5
-
6
-
1
-
5
-
6
-
3
-
2
-
3
-
3
-
2
-
2
-
6
-
4
-
12
-
3
-
5
-
5
-
4
-
2
-
5
-
2
-
11
-
4
-
2
-
1