PorterDuffXferMode的一些使用問題
一 PorterDuff.Mode使用問題
1.1 PorterDuff.Mode.CLEAR
-
正常效果
android_26_PorterDuff_Mode_CLEAR
-
targetSdkVersion 28
android_28_PorterDuff_Mode_CLEAR
1.2 PorterDuff.Mode
PorterDuff.Mode 官方效果
https://developer.android.com/reference/android/graphics/PorterDuff.Mode.html
1.2 PorterDuffXfermode 在Android 27 和 28 的實際效果
-
PorterDuffXfermode_27
PorterDuffXfermode_27 -
PorterDuffXfermode_28
PorterDuffXfermode_28
二 繪制時 canvas 畫布不同導致的問題
after change another canvas ,PorterDuffXfermode(PorterDuff.Mode.CLEAR) is not work
創(chuàng)建 另一個 畫布
//保存沒有背景的截圖
screenShotBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
mScreenShotCanvas = Canvas(screenShotBitmap)
dispatchDraw
override fun dispatchDraw(canvas: Canvas?) {
...
//7.繪制蒙版
drawMask(canvas)
....
//截圖
mScreenShotCanvas?.let { canvas ->
...
//7.繪制蒙版
drawMask(canvas, true)
...
}
...
}
問題 傳入的canvas 不同
/**
* 繪制蒙版
*
*/
private fun drawMask(canvas: Canvas, shotScreen: Boolean = false) {
try {//qtip rl_frame_content -> 相框外層容器
rl_frame_content?.let {
//先獲取相框外層容器的位置
val rlLeft = it.left
val rlTop = it.top
mGpuIV?.let { gpuIv ->
mMaskBitmap?.let { mask ->
//獲取相片和相框外側之間的位置關系
val gpuIvLeft = rl_gpu_iv_content_trim.left
val gpuIvTop = rl_gpu_iv_content_trim.top
val gpuIvWidth = rl_gpu_iv_content_trim.width
val gpuIvHeight = rl_gpu_iv_content_trim.height
val newWidth = gpuIvWidth - 2 * mMaskMargin
val newHeight = gpuIvHeight - 2 * mMaskMargin
//縮放后的蒙版(根據(jù)圖片的大小調整蒙版大小)
if (mScaledMaskBitmap == null) {
mScaledMaskBitmap = BitmapUtils.scaleBitmapInMaxWidthOrHeight(mask, newWidth, newHeight)
}
mScaledMaskBitmap?.let { scaleMask ->
//繪制mask
val left = rlLeft.toFloat() + gpuIvLeft
val top = rlTop.toFloat() + gpuIvTop
//1.離屏畫布
val save = canvas.saveLayer(left, top, left + gpuIvWidth, top + gpuIvHeight, null, Canvas.ALL_SAVE_FLAG)
//2.繪制帶顏色蒙版 創(chuàng)建大小和 rl_frame_content 一樣的蒙版
val dstBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
//創(chuàng)建蒙版畫布
val dstCav = Canvas(dstBitmap)
//蒙版顏色
dstCav.drawColor(mMaskColor)
canvas.drawBitmap(dstBitmap, left, top, null)
//3.蒙版掏空出透明形狀區(qū)域
val paintMask = Paint()
paintMask.isAntiAlias = true
paintMask.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
//蒙版位置居中
canvas.drawBitmap(scaleMask, left + (gpuIvWidth - scaleMask.width) / 2, top + (gpuIvHeight - scaleMask.height) / 2, paintMask)
//4.畫布恢復
canvas.restoreToCount(save)
} }
}
}
} catch (e: Exception) {
QLogger.e(e)
}
}
需要的效果
蒙版
蒙版形狀.png
截圖時實際效果
蒙版形狀失敗.png
并不是 paintMask.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
無效 而是 clear的區(qū)域不是 圖片的非透明區(qū)而是 整個圖片
- 解決問題
// QTIP: 2019-07-23 修改
PorterDuff.Mode.CLEAR
為 PorterDuff.Mode.DST_OUT 或者 PorterDuff.Mode.XOR
待解決疑問 : Android api 28 以下 傳入有bitmap的canvas 繪制時 PorterDuff.Mode.CLEAR 無效
參考
https://stackoverflow.com/questions/10494442/android-paint-porterduff-mode-clear?rq=1
https://issuetracker.google.com/issues/111819103
關聯(lián)下 ViewOutlineProvider
/**
* Interface by which a View builds its {@link Outline}, used for shadow casting and clipping.
*/
public abstract class ViewOutlineProvider {
...