Android clippling使用
Android clipping
Clipping
在Android中如果多個view嵌套的會引起overdraw,很多時候一些view被覆蓋了,對用戶是不可見的,但是依然會進行繪制,這個時候使用clipping來進行對不可見區域進行裁剪,可以減少overdraw提高gpu的效率。
如下圖所示:使用clipping rectangle就可以實現對view的裁剪。
使用clipping能達到的效果
clipping的使用也很簡單:
1、裁剪出想要渲染的部分
如下只想渲染出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
上面代碼中先拿到背景和圓柱的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中用一下方式使用
給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.clippingexampleimport 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
總結
以上是生活随笔為你收集整理的Android clippling使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《中国迈向新一代人工智能》全文来了。道翰
- 下一篇: Keycloak实现手机验证码登录