Android Custom View неправильно обрабатывает прозрачность / альфа
Я рисую собственный вид. В этом представлении я использую два разных объекта рисования и пути для рисования на холсте. Я в основном рисую две фигуры, которые перекрываются. После того, как я добавлю альфу, перекрывающаяся часть будет темнее, чем остальная часть изображения. Это нежелательно, но я не уверен, как это исправить.
Это фрагмент моего кода, чтобы показать, как я использую альфа в моем NewButtonView.java
Paint paint = new Paint();
int color = 0x33ffffff;
int borderColor = 0xFF000000;
paint.setColor(color);
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.FILL);
Примерно через 31 минуту в этом видео Google I/O... они показывают мой желаемый эффект.
Они в основном показывают это изображение:
Добавьте прозрачность и получите это изображение: НЕОБХОДИМЫЙ РЕЗУЛЬТАТ
Они в конечном итоге с этим: желаемый результат
У кого-нибудь есть идеи о том, как получить этот желаемый эффект?
2 ответа
Как упоминалось в видео, вы бы использовали Canvas#saveLayerAlpha(....)
за это. Вы также можете получить аналогичный эффект, не используя его. Я буду обсуждать это позже.
Давайте создадим примерное представление:
public class SampleView extends View {
// Declare Paint objects
Paint paintColor, paintBorder;
public SampleView(Context context) {
super(context);
// Initialize and set up Paint objects
paintColor = new Paint();
paintBorder = new Paint();
paintColor.setAntiAlias(true);
paintBorder.setAntiAlias(true);
paintBorder.setColor(Color.BLACK);
paintBorder.setStyle(Style.STROKE);
paintBorder.setStrokeWidth(10);
// Just a random image to 'see' the difference
setBackground(getResources().getDrawable(R.drawable.hor_lines));
}
@Override
protected void onDraw(Canvas canvas) {
// Save layer alpha for Rect that covers the view : alpha is 90 / 255
canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 90,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
// Draw first circle, and then the border
paintColor.setColor(Color.RED);
canvas.drawCircle(getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 20, paintColor);
canvas.drawCircle(getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 15, paintBorder);
// Draw second circle, and then the border
paintColor.setColor(Color.BLUE);
canvas.drawCircle(2 * getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 20, paintColor);
canvas.drawCircle(2 * getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 15, paintBorder);
// Finally, restore the canvas
canvas.restore();
}
}
Что просходит:
Вне экрана растровое изображение выделяется, когда
saveLayerAlpha(....)
называется.Все операции рисования происходят на этом растровом изображении.
когда
canvas.restore()
Это растровое изображение передается на экранную основу, а альфа-значение, которое мы указали вsaveLayerAlpha(....)
применяется к закадровому растровому изображению.
(Я думаю) Ниже приведен эквивалентный способ создания этого эффекта без использования saveLayerAlpha(....)
:
public class SView extends View {
Paint paintColor, paintBorder, paintAlpha;
Bitmap toDrawOn;
public SView(Context context) {
super(context);
paintAlpha = new Paint();
paintAlpha.setColor(Color.parseColor("#90FFFFFF"));
paintAlpha.setAntiAlias(true);
....
....
}
@Override
protected void onDraw(Canvas canvas) {
if (toDrawOn == null) {
// Create a new Bitmap
toDrawOn = Bitmap.createBitmap(getWidth(), getHeight(),
Config.ARGB_8888);
// Create a new Canvas; drawing operations
// will happen on 'toDrawOn'
Canvas offScreen = new Canvas(toDrawOn);
// First circle
paintColor.setColor(Color.RED);
offScreenCanvas.drawCircle(getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 20, paintColor);
offScreenCanvas.drawCircle(getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 15, paintBorder);
// Second circle
paintColor.setColor(Color.BLUE);
offScreenCanvas.drawCircle(2 * getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 20, paintColor);
offScreenCanvas.drawCircle(2 * getWidth() / 3, getHeight() / 2,
getWidth() / 4 - 15, paintBorder);
// Draw bitmap 'toDrawOn' to canvas using 'paintAlpha'
canvas.drawBitmap(toDrawOn, 0, 0, paintAlpha);
} else {
// 'toDrawOn' is not null; draw it
canvas.drawBitmap(toDrawOn, 0, 0, paintAlpha);
}
}
}
Выход:
Просто для справки, базовый контейнер на изображении выше является LinearLayout
с фоном, установленным на этот JPEG: Ссылка.
И, drawable используется в качестве фона SampleView:
// Just a random image to 'see' the difference
setBackground(getResources().getDrawable(R.drawable.hor_lines));
взято из: здесь.
Вы можете нарисовать все в растровом изображении с полной альфа, а затем изменить альфа растрового изображения
(Извините, это больше комментарий, чем ответ, но переполнение стека не позволит мне оставлять комментарии)