IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android clippling使用 -> 正文阅读

[移动开发]Android clippling使用

Android clipping

Clipping

在Android中如果多个view嵌套的会引起overdraw,很多时候一些view被覆盖了,对用户是不可见的,但是依然会进行绘制,这个时候使用clipping来进行对不可见区域进行裁剪,可以减少overdraw提高gpu的效率。
如下图所示:使用clipping rectangle就可以实现对view的裁剪。
在这里插入图片描述

使用clipping能达到的效果
在这里插入图片描述

clipping的使用也很简单:
1、裁剪出想要渲染的部分

canvas.clipRect(clipRectLeft,clipRectTop, clipRectRight,clipRectBottom)

如下只想渲染出300*300大小的区域


        val rect2 = Rect(100, 100, 400, 400)
        canvas.clipRect(rect2)
        canvas.drawBitmap(bgBitmap, 0f, 0f, null)

在这里插入图片描述

2、裁剪出不需要渲染的部分

canvas.clipOutRect(clipRectLeft,clipRectTop, clipRectRight,clipRectBottom)

如下抠掉中间300*300的区域

        val rect2 = Rect(100, 100, 400, 400)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            canvas.clipRect(rect2,Region.Op.DIFFERENCE)
        } else {
            canvas.clipOutRect(
                rect2
            )
        }
        canvas.drawBitmap(bgBitmap, 0f, 0f, null)

在这里插入图片描述

可以定义一个剪辑区域,并保存该状态。 然后平移画布,添加剪辑区域并旋转。 做一些绘图后,可以恢复原来的裁剪状态,可以继续做不同的平移和倾斜变换,如图所示。
在这里插入图片描述

clip方法
在这里插入图片描述
clip和clipOut方法的区别:通过clip的区域是显示的区域,通过clipOut方法是把该区域不显示。

实例

在这里插入图片描述

其实是两张图片叠加在一起形成的,后面是一个全屏的背景图,加上一个椭圆柱。

在这里插入图片描述

两张图片叠加的部分对用户不可见,属于过度绘制区,为了减少过度绘制对性能的影响可以用clipping方法对重叠的部分进行裁剪。
裁剪
可以先渲染出底部圆柱,然后再从背景中抠出底部区域的大小不用渲染,最后渲染背景:
在这里插入图片描述

上图中黑色区域代表clipOut区域
通过计算出底部圆柱的高度和宽度来对背景图进行一次裁剪这里自定义一个ClipImageDrawable继承了Drawable

class ClippedImageDrawable(context: Context) : Drawable() {
    companion object {
        private const val TAG = "ClippedImageDrawable"
    }

    private var bgBitmap: Bitmap =
        BitmapFactory.decodeResource(context.resources, R.drawable.book_detail_bg)
    private val shelfBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.bookshelf)
    override fun draw(canvas: Canvas) {
        Log.d(TAG, "width ${bounds.width()}  height ${bounds.height()}")
        bounds.width()
        val top = 0.71 * bounds.height()
        val bottom = bounds.height()
        val rect = Rect(0, top.toInt(), shelfBitmap.width, bottom)
        canvas.drawBitmap(shelfBitmap, 0f, top.toFloat(), null)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            canvas.clipRect(rect, Region.Op.DIFFERENCE)
        } else {
            canvas.clipOutRect(rect)
        }
        canvas.drawBitmap(bgBitmap, 0f, 0f, null)

    }

    override fun setAlpha(alpha: Int) {
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {

    }
    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }
}

上面代码中先拿到背景和圆柱的bitmap对象,然后再背景图中裁剪出一个跟圆柱大小的rect,再执行

       if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            canvas.clipRect(rect, Region.Op.DIFFERENCE)
        } else {
            canvas.clipOutRect(rect)
        }

上面的canvas.clipRect(rect, Region.Op.DIFFERENCE)就是把rect和背景相交的部分裁剪,在Build.VERSION_CODES.O以上的版本可以使用canvas.clipOutRect(rect)方法。
注意上面代码的顺序:
1、先用canvas.drawBitmap底部的圆柱。
2、使用clip裁剪出圆柱图片的rect。
3、最后再绘制背景bitmp
在activity中用一下方式使用

val drawable = ClippedImageDrawable(this)
val imageView = ImageView(this).apply {
    val param = FrameLayout.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT
    )
    scaleType = ImageView.ScaleType.FIT_XY
    layoutParams = param
    setImageDrawable(drawable)
}
setContentView(imageView)

给imageView设置drawable,效果如下:
在这里插入图片描述

看上面效果图中,圆柱和背景的相交处有两个空白,这是因为圆柱图片是一个长方形并且顶部有两处空白,这样绘制出来就达不到设计给的效果。这里的原因是在使用clip的时候用的是一个rect形状,要达到背景和圆柱融合的效果,使用rect形状是不行的。
可以使用clipoutPath方法来裁剪出想要的区域。
上面圆柱顶部的弧度可以用二次赛贝尔曲线来实现https://www.tweenmax.com.cn/tool/bezier/。
在这里插入图片描述

绘制二阶Bezier曲线
/** * 从上一个点开始,绘制二阶Bezier曲线 * (x1,y1)为控制点, (x2,y2)为终点 * 如果之前没有调用过 moveTo(),则默认从 (0,0)作为起点绘制。 /
public void quadTo(float x1, float y1, float x2, float y2) ;
/
* * 和quadTo相同,只不过这里是使用的是相对坐标。 */
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)

结合path和贝塞尔曲线绘制出底部的区域
path.moveTo(0f, top.toFloat()+40)
path.quadTo(
(bounds.width() / 2).toFloat(), top.toFloat()-50, bounds.width().toFloat(),
(top + 60).toFloat()
)
path.lineTo(bounds.width().toFloat(), bounds.height().toFloat())
path.lineTo(0f, bounds.height().toFloat())

如下图对底部区域执行clipOut之后
在这里插入图片描述

最终实现代码

package com.example.android.clippingexample

import android.content.Context
import android.graphics.*
import android.graphics.drawable.Drawable
import android.os.Build
import android.util.Log

/**
 * create by 胡汉君
 * date 2021/8/21 17:39
 */
class ClippedImageDrawable(context: Context) : Drawable() {
    companion object {
        private const val TAG = "ClippedImageDrawable"
    }

    private var bgBitmap: Bitmap =
        BitmapFactory.decodeResource(context.resources, R.drawable.book_detail_bg)
    private val shelfBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.bookshelf)
    private val path = Path()
    override fun draw(canvas: Canvas) {
        Log.d(TAG, "width ${bounds.width()}  height ${bounds.height()}")
        path.reset()
        bounds.width()
        val top = 0.71 * bounds.height()
        path.moveTo(0f, top.toFloat()+40)
        path.quadTo(
            (bounds.width() / 2).toFloat(), top.toFloat()-50, bounds.width().toFloat(),
            (top + 60).toFloat()
        )
        path.lineTo(bounds.width().toFloat(), bounds.height().toFloat())
        path.lineTo(0f, bounds.height().toFloat())
        path.close()
        canvas.drawBitmap(shelfBitmap, 0f, top.toFloat(), null)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            canvas.clipPath(path, Region.Op.DIFFERENCE)
        } else {
            canvas.clipOutPath(path)
        }
        canvas.drawBitmap(bgBitmap, 0f, 0f, null)

    }

    override fun setAlpha(alpha: Int) {
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {

    }

    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }
}

效果

在这里插入图片描述

参考
1、https://medium.com/android-news/simplifying-layouts-with-layer-list-drawables-2f750ea1504e
2、https://blog.zen.ly/implementing-custom-drawables-part-1-5530a98cefc9
3、https://developer.android.google.cn/codelabs/advanced-android-kotlin-training-clipping-canvas-objects?hl=vi#0

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:48:38  更:2021-08-23 16:49:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:01:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码