先看下效果
实现这种效果,我所知道的有两种办法,而且都很简单,一是使用着色器Shade,第二是使用PorterDuffXfermode。
着色器是一个非常好玩的东西,Shade是个基类,子类有五个,最常用的就是BitmapShader,相当于给画笔设置了一个图片,在调用drawXXX绘图的时候,会呈现出这个图片所对应的位置。
Shade实现
下面是使用着色器实现的步骤,首先给paint设置setShader,当调用drawCircle绘制圆时,圆中心点的坐标会被绘制成图片中所对应位置,比如中心点坐标是10,10,那么就会从图片10,10的位置开始绘制。
@RequiresApi(Build.VERSION_CODES.P)
class MiniLoading @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
var srcBitmap: Bitmap;
var currentX: Float = 0f;
var currentY: Float = 0f;
init {
srcBitmap = BitmapFactory.decodeResource(resources, R.drawable.back)
post {
var ma = Matrix()
ma.setScale(width / srcBitmap.width.toFloat(), width / srcBitmap.width.toFloat())
srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.width, srcBitmap.height, ma, false)
invalidate()
}
}
override fun onDraw(canvas: Canvas) {
var paint = Paint()
var bitmapShader = BitmapShader(srcBitmap, Shader.TileMode.MIRROR, Shader.TileMode.CLAMP)
paint.setShader(bitmapShader)
canvas.drawCircle(currentX,currentY,100f,paint)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action==MotionEvent.ACTION_MOVE){
this.currentX = event.x!!
this.currentY = event.y!!
invalidate()
}
return true;
}
}
那么当图片大小是200*200时候,当绘制到300的时候,该怎么办,这就是BitmapShader构造器中TileMode的作用,取值有以下三个
-
TileMode.CLAMP:拉伸最后一个像素去铺满剩下的地方;
-
TileMode.MIRROR:通过镜像翻转铺满剩下的地方;
-
TileMode.REPEAT:重复图片平铺整个画面。
对应的我们还可以绘制炫酷的字体。
var paint = Paint()
var bitmapShader = BitmapShader(srcBitmap, Shader.TileMode.MIRROR, Shader.TileMode.CLAMP)
paint.setShader(bitmapShader)
paint.textSize=100f
canvas.drawText("听风逝夜",width/2.toFloat(),height/2.toFloat(),paint)
PorterDuffXfermode实现
上一张看烂了也不会的图,PorterDuffXfermode就相当于PS中选区相交,相减,实现本效果用到的是SRC_IN
首先在canvas绘制一个圆圈,在设置xfermode为SRC_IN,在绘制一个全屏的图片,那么,和圆对应位置的图片就会被保留下,其他位置会被删除,这样不停移动currentX、currentY,就形成了望远镜效果。
override fun onDraw(canvas: Canvas) {
val paint = Paint()
canvas.drawCircle(
currentX,
currentY,
100f,
paint
)
val rect = Rect(0, 0, this.width, this.height)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(srcBitmap, rect, rect, paint)
}
利用这个特性还可以实现刮奖的效果。