canvas.clipRect(left , top ,right,bottom) 裁切函数
canvas.clipPath() // 切割图形
clipOutRect / clipOutPath 切出,切出的是不需要的
clipPath(path) 切出来会有毛边 锯齿,会把指定范围的显示出来,其他的不显示,按像素px进行裁切
如果需要精细显示 可以使用xfermode
canvas 几何变换(改变坐标系)
translate (x,y) 平移
rotate(degree) 指定角度旋转
scale(x,y) 缩/放
skew(x,y) 侧切
canvas.tranlate
canvas.drawXXX 先变换 移动 再绘制
canvas.rotate
canvas.translate 先旋转再平移,平移不是按照原先的坐标移动 而是沿着旋转方向的x y 移动
这些操作的是canvas
canvas.scale
canvas.drawXXX 先放缩,然后绘制,绘制时放缩后的位置
Matrix 的几何变换
相比于canvas 它有两套写法 比如 preScale = canvas.scale /postScale
post 基于变换前的坐标系进行变换
Camera类:
rotate(x,y,z) 旋转 // 旋转最好指定轴心,没有轴心默认会是0,0位置
rotateX
rotateY
rotateZ
三维坐标,X不变,Y轴往上是正向,Z轴为交互点,相当于投影
camera.applyToCanvas(canvas) 绑定
canvas.translate
camera.applyToCanvas(canvas)
canvas.translate
先移动canvas 然后 camera完成后 再移动回来 得到正形 ,思路得相反,canvas 轴心会变换
示例:
canvas.translate(BITMAP_PADDING + BITMAP_SIZE /2, BITMAP_PADDING + BITMAP_SIZE /2, ) camera.applyToCanvas(canvas) canvas.translate(- (BITMAP_PADDING + BITMAP_SIZE /2),- (BITMAP_PADDING + BITMAP_SIZE /2), )
会出现弧形效果 需要改变camera的Z值
camera.setLocation(x,y,z) z默认-8f 英寸为单位 1英寸= 72像素
手机像素不同,所需要调整的Z轴调整的也不同 需要动态计算
clipRect 裁切需要判断是否进行三维变化或者canvas的x y 是否已经变换
cli[pRect后,只保留裁切的,其他的内容都会丢弃,代码也就执行失效,需要canvas.save
package com.example.androidstudiogiraffe.view
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Camera
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.view.View
import com.example.androidstudiogiraffe.R
import com.future.startstudyproject.utils.dp
private val BITMAP_SIZE = 200.dp
private val BITMAP_PADDING = 100.dp
class CameraView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val bitmap = getBitmap(BITMAP_SIZE.toInt())
private val camera = Camera()
private val path = Path().apply {
addOval(
BITMAP_PADDING, BITMAP_PADDING, BITMAP_PADDING + BITMAP_SIZE,
BITMAP_PADDING + BITMAP_SIZE, Path.Direction.CCW
)
}
init {
camera.rotateX(12f)
camera.setLocation(0f, 0f, -6 * resources.displayMetrics.density)
}
override fun onDraw(canvas: Canvas) {
// canvas.clipRect(BITMAP_PADDING, BITMAP_PADDING, BITMAP_PADDING + BITMAP_SIZE /2 .toFloat() ,
// BITMAP_PADDING + BITMAP_SIZE / 2 .toFloat())
// canvas.clipPath(path)
//上
canvas.save()
canvas.translate(BITMAP_PADDING + BITMAP_SIZE / 2, BITMAP_PADDING + BITMAP_SIZE / 2)
canvas.rotate(-30f) //旋转回来
//旋转
// canvas.clipRect(
// -BITMAP_SIZE / 2,
// -BITMAP_SIZE / 2,
// BITMAP_SIZE / 2,
// 0f
// )
//未旋转
canvas.clipRect(
-BITMAP_SIZE ,
-BITMAP_SIZE,
BITMAP_SIZE,
0f
)
canvas.rotate(30f) //旋转30度
canvas.translate(-(BITMAP_PADDING + BITMAP_SIZE / 2), -(BITMAP_PADDING + BITMAP_SIZE / 2))
canvas.drawBitmap(bitmap, BITMAP_PADDING, BITMAP_PADDING, paint)
canvas.restore()
//下
canvas.save()
canvas.translate(BITMAP_PADDING + BITMAP_SIZE / 2, BITMAP_PADDING + BITMAP_SIZE / 2)
canvas.rotate(-30f) //旋转回来
camera.applyToCanvas(canvas)
// canvas.clipRect(
// -BITMAP_SIZE / 2,
// 0f,
// BITMAP_SIZE / 2,
// BITMAP_SIZE / 2
// )
//未旋转
canvas.clipRect(
-BITMAP_SIZE ,
0f,
BITMAP_SIZE,
BITMAP_SIZE
)
canvas.rotate(30f) //旋转30度
canvas.translate(-(BITMAP_PADDING + BITMAP_SIZE / 2), -(BITMAP_PADDING + BITMAP_SIZE / 2))
canvas.drawBitmap(bitmap, BITMAP_PADDING, BITMAP_PADDING, paint)
canvas.restore()
}
private fun getBitmap(width: Int): Bitmap {
val option = BitmapFactory.Options()
option.inJustDecodeBounds = true
BitmapFactory.decodeResource(resources, R.drawable.head_image, option)
option.inJustDecodeBounds = false
option.inDensity = option.outWidth
option.inTargetDensity = width
return BitmapFactory.decodeResource(resources, R.drawable.head_image, option)
}
}