欲实现一个翻书的特效,那么就需要实现折叠效果,通过camera的旋转来实现
知识点:
- 摄像头的旋转和移动。
Camera.rotateX(45f),canvas沿着x轴旋转45度 Camera.setLocation(0f, 0f, -6 * resources.displayMetrics.density) 摄像头的x,y坐标不变,沿着z轴远离原点方向移动6英寸,之所以要在乘以像素密度,是为了兼容不同屏幕的差异,是的显示效果尽可能统一
-
canvas.translate方法,移动画布,关于这个方法,许多小伙伴会觉得找不到规律,每次移动,旋转经常达不到想要的效果,只能通过不断地尝试,最终才能达到想要的效果。这里分享一下我的经验。首先,android渲染view的时候,是把view放到一个三维的坐标系里的,view坐标系小伙伴都能理解。原点在左上角,X轴向右为正,Y轴向下为正。而Z轴其实就是垂直View坐标系的原点,向屏幕内方向为正。你可以简单的把虚拟camera想想成自己的眼睛,只不过,这只眼睛始终在屏幕左上角垂直于屏幕方向。在移动的时候,你可以想象成把眼睛移动到你指定坐标的正上方。用完了记得把眼睛移回去 canvas.rotate(),旋转画布 canvas.clipRect() 裁剪画布
-
camera.applyToCanvas(canvas) 实现画布的z轴方向的翻转效果
效果如下:
源码:
class FoldView : View {
constructor(context: Context?) : super(context) {
}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
constructor(
context: Context?,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
private val camera = Camera().apply {
//虚拟摄像头旋转45度
rotateX(45f)
//设置虚拟camera到屏幕的距离,这样代码是为了适配不同类型屏幕设备
setLocation(0f, 0f, -6 * resources.displayMetrics.density)
}
private val paint = Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE
strokeWidth = 40f
textSize = 64f
color = Color.GRAY
}
private val bmp = createBmp(600)
private val x = 100f
private val y = 100f
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
bmp?.also {
with(canvas) {
//绘制上半部分
save()
//将camera移动到要画的图片中心上方
translate(x + bmp.width / 2, y + bmp.height / 2)
//canvas旋转-20度,为了实现斜切效果
rotate(-20f)
//截取部分区域,大小只要能保证足够图片上半部分显示即可
clipRect(-600, -600, 600, 0)
//canvas再旋转回来
rotate(20f)
//将虚拟摄像头移动回原点
translate(-(x + bmp.width) / 2, -(y + bmp.height / 2))
//开始画图
drawBitmap(it, x, y, paint)
restore()
//绘制下半部分
save()
//将camera移动到要画的图片中心上方
translate(x + bmp.width / 2, y + bmp.height / 2)
rotate(-20f)
//实现折叠效果
camera.applyToCanvas(this)
//截取部分区域,大小只要能保证足够图片下半部分显示即可
clipRect(-600, 0, 600, 600)
rotate(20f)
//将虚拟摄像头移动回原点
translate(-(x + bmp.width) / 2, -(y + bmp.height / 2))
drawBitmap(it, x, y, paint)
restore()
}
}
}
private fun createBmp(height: Int): Bitmap? {
return try {
BitmapFactory.Options().apply {
inJustDecodeBounds = true //指计算图片的轮廓
}.let {
BitmapFactory.decodeResource(resources, R.drawable.img_txt, it)
it.inJustDecodeBounds = false
//加载图片时,将原始图片按照比例压缩
it.inDensity = it.outHeight
it.inTargetDensity = height
BitmapFactory.decodeResource(resources, R.drawable.img_txt, it)
}
} catch (e: Exception) {
e.printStackTrace()
null
}
}
}