Android自定义View-图片折叠效果

本文介绍了如何在Android中利用Camera类的rotateX和setLocation方法实现翻书特效的折叠效果,通过canvas的translate、rotate和clipRect操作,以及camera.applyToCanvas以控制z轴翻转。作者分享了在处理视图坐标系和屏幕适配中的关键技巧。
摘要由CSDN通过智能技术生成

欲实现一个翻书的特效,那么就需要实现折叠效果,通过camera的旋转来实现

知识点:

  1. 摄像头的旋转和移动。
    Camera.rotateX(45f),canvas沿着x轴旋转45度
    Camera.setLocation(0f, 0f, -6 * resources.displayMetrics.density)
    摄像头的x,y坐标不变,沿着z轴远离原点方向移动6英寸,之所以要在乘以像素密度,是为了兼容不同屏幕的差异,是的显示效果尽可能统一
  2. canvas.translate方法,移动画布,关于这个方法,许多小伙伴会觉得找不到规律,每次移动,旋转经常达不到想要的效果,只能通过不断地尝试,最终才能达到想要的效果。这里分享一下我的经验。首先,android渲染view的时候,是把view放到一个三维的坐标系里的,view坐标系小伙伴都能理解。原点在左上角,X轴向右为正,Y轴向下为正。而Z轴其实就是垂直View坐标系的原点,向屏幕内方向为正。你可以简单的把虚拟camera想想成自己的眼睛,只不过,这只眼睛始终在屏幕左上角垂直于屏幕方向。在移动的时候,你可以想象成把眼睛移动到你指定坐标的正上方。用完了记得把眼睛移回去
    canvas.rotate(),旋转画布
    canvas.clipRect() 裁剪画布
    
  3. 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
        }
    }
}

ToggleExpandLayout是一个可折叠和展开子view的开关布局控件。它可以将它的子view以阶梯式的展开。项目地址:https://github.com/fenjuly/ToggleExpandLayout 效果图:如何使用<com.fenjuly.mylibrary.ToggleExpandLayout             android:id="@ id/toogleLayout"             android:layout_width="wrap_content"             android:layout_height="80dp"             >             <TextView                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:text="view 1"/>             <TextView                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:text="view 2"/>             <TextView                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:text="view"/>                      </com.fenjuly.mylibrary.ToggleExpandLayout>注意,由于ToggleExpandLayout的本质是个FrameLayout,所以必须将其高度设置为大于所有子view展开状态的高度,不能设为wrap_content。为了解决这个问题,你可以将ToggleExpandLayout的外面在加个DropDownLayout:<com.fenjuly.mylibrary.DropDownLayout         android:layout_width="match_parent"         android:layout_height="match_parent"         >         <com.fenjuly.mylibrary.ToggleExpandLayout             android:id="@ id/toogleLayout"             android:layout_width="wrap_content"             android:layout_height="wrap_content"             >             <TextView                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:text="view 1"/>              <TextView                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:text="view 2"/>               <TextView                 android:layout_width="wrap_content"                 android:layout_height="wrap_content"                 android:text="view"/>                              </com.fenjuly.mylibrary.ToggleExpandLayout> </com.fenjuly.mylibrary.DropDownL
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值