日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 自定义View 实例2_Clipping Canvas

發布時間:2023/12/8 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 自定义View 实例2_Clipping Canvas 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一篇 Android 自定義View 實例_ 畫圖? 參考:?https://blog.csdn.net/whjk20/article/details/115639448

這里是Canvas 的裁剪 (同時可以控制可見性, 主要是考慮到繪制的性能)

目錄

1. 相關概念

(1)Render 渲染

(2)Clipping 裁剪 (只繪制可見部分,提升性能)

(3)overdraw 過度繪制 (減少過度繪制,提升性能)

2. 屏幕分辯率

3. The Drawing Algorithm

4. Clipping methods

5. 實例

5.1 效果圖:

5.2 代碼


1. 相關概念

(1)Render 渲染

https://developer.android.com/topic/performance/rendering

(2)Clipping 裁剪 (只繪制可見部分,提升性能)

https://en.wikipedia.org/wiki/Clipping_%28computer_graphics%29

(3)overdraw 過度繪制 (減少過度繪制,提升性能)

https://developer.android.com/topic/performance/rendering/overdraw.html
過度繪制是指系統在渲染單個幀的過程中多次在屏幕上繪制某一個像素。
例如,如果我們有若干界面卡片堆疊在一起,每張卡片都會遮蓋其下面一張卡片的部分內容。

您可以采取以下幾種策略來減少甚至消除過度繪制:

  • (1)移除布局中不需要的背景。
  • (2)使視圖層次結構扁平化。
  • (3)降低透明度:

例如,如需獲得灰色文本,您可以在 TextView 中繪制黑色文本,再為其設置半透明的透明度值。但是,您可以簡單地通過用灰色繪制文本來獲得同樣的效果,而且能夠大幅提升性能。

2. 屏幕分辯率

Smallest Screen Width -> 480 ?-> sw-480
Screen Width -> 480 ?->w-480


3. The Drawing Algorithm

?

  • ?canvas.save() ?保存當前狀態
  • canvas.translate() 移動到特定的坐標
  • canvas.clipRect()/clipOutRect ?相對當前畫布,不進行繪制的部分(裁剪部分)?
  • ?draw
  • ?canvas.restore
  • What are advantages of moving the canvas instead of moving the objects?
    Simplicity ,safty, less error prone
    Easier to unwind transformations


    4. Clipping methods

    1. save current state: canvas.save()
    2. Translate origin to row/column coords: canvas.translate()
    3. Apply transformations to path
    4. Apply clipping: canvas.clipPath(path) 重疊的部分只畫path
    5. Draw shape: drawClippedRectangle or drawText()
    6. Restore previous canvas state: canvas.restore()?

    5. 實例

    5.1 效果圖:

    5.2 代碼

    主要是自定義View,? ?主要是onDraw() 里面的10個方法, 對應上面效果圖

    package com.example.clippingexampleimport android.content.Context import android.graphics.* import android.os.Build import android.util.AttributeSet import android.view.Viewclass ClippedView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) {private val paint = Paint().apply {// Smooth out edges of what is drawn without affecting shape.isAntiAlias = truestrokeWidth = resources.getDimension(R.dimen.strokeWidth)textSize = resources.getDimension(R.dimen.textSize)}private val path = Path() //把已經繪制的軌跡保存到本地//裁剪矩形private val clipRectRight = resources.getDimension(R.dimen.clipRectRight)private val clipRectBottom = resources.getDimension(R.dimen.clipRectBottom)private val clipRectTop = resources.getDimension(R.dimen.clipRectTop)private val clipRectLeft = resources.getDimension(R.dimen.clipRectLeft)//矩形內部private val rectInset = resources.getDimension(R.dimen.rectInset)private val smallRectOffset = resources.getDimension(R.dimen.smallRectOffset)//在矩形的圓private val circleRadius = resources.getDimension(R.dimen.circleRadius)private val textOffset = resources.getDimension(R.dimen.textOffset)private val textSize = resources.getDimension(R.dimen.textSize)//行列位置private val columnOne = rectInsetprivate val columnTwo = columnOne + rectInset + clipRectRightprivate val rowOne = rectInsetprivate val rowTwo = rowOne + rectInset + clipRectBottomprivate val rowThree = rowTwo + rectInset + clipRectBottomprivate val rowFour = rowThree + rectInset + clipRectBottomprivate val textRow = rowFour + (1.5f * clipRectBottom)private val rejectRow = rowFour + rectInset + 2*clipRectBottomprivate var rectF = RectF(rectInset,rectInset,clipRectRight - rectInset,clipRectBottom - rectInset)override fun onDraw(canvas: Canvas) {super.onDraw(canvas)drawBackAndUnclippedRectangle(canvas)drawDifferenceClippingExample(canvas)drawCircularClippingExample(canvas)drawIntersectionClippingExample(canvas)drawCombinedClippingExample(canvas)drawRoundedRectangleClippingExample(canvas)drawOutsideClippingExample(canvas)drawSkewedTextExample(canvas)drawTranslatedTextExample(canvas)drawQuickRejectExample(canvas)}private fun drawClippedRectangle(canvas: Canvas){// 0, 0, 90/120, 90/120 裁剪一個矩形(正方形)canvas.clipRect(clipRectLeft, clipRectTop, clipRectRight, clipRectBottom)canvas.drawColor(Color.WHITE) //先繪制背景為白色//繪制紅線 , 開始點的x,y坐標, 終點的x,y坐標paint.color=Color.REDcanvas.drawLine(clipRectLeft,clipRectTop,clipRectRight,clipRectBottom, paint)//繪制一個圓, 顏色為綠色,圓心坐標及半徑paint.color=Color.GREENcanvas.drawCircle(circleRadius,clipRectBottom-circleRadius,circleRadius,paint)//繪制文本paint.color=Color.BLUE// Align the RIGHT side of the text with the origin. 參考對象為當前繪制區域, 右對齊,即文本靠齊右邊框paint.textSize=textSizepaint.textAlign=Paint.Align.RIGHTcanvas.drawText(context.getString(R.string.clipping), clipRectRight, textOffset, paint)}private fun drawBackAndUnclippedRectangle(canvas: Canvas) {canvas.drawColor(Color.GRAY) //繪制背景為灰色canvas.save() //保存canvascanvas.translate(columnOne, rowOne) //移動canvas到下一個繪制點drawClippedRectangle(canvas) //繪制canvas.restore() //恢復canvas到原來的位置}private fun drawDifferenceClippingExample(canvas: Canvas) {canvas.save()// Move the origin to the right for the next rectangle.canvas.translate(columnTwo,rowOne)// Use the subtraction of two clipping rectangles to create a frame.canvas.clipRect(2 * rectInset,2 * rectInset,clipRectRight - 2 * rectInset,clipRectBottom - 2 * rectInset)// The method clipRect(float, float, float, float, Region.Op// .DIFFERENCE) was deprecated in API level 26. The recommended// alternative method is clipOutRect(float, float, float, float),// which is currently available in API level 26 and higher.if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)// 使得這部分保留灰色(即這部分不進行繪制?????, 還是把這層放在最上面繪制???)canvas.clipRect(4 * rectInset,4 * rectInset,clipRectRight - 4 * rectInset,clipRectBottom - 4 * rectInset,Region.Op.DIFFERENCE //差異)else {// 使得這部分保留灰色(即這部分不進行繪制?????)canvas.clipOutRect(4 * rectInset,4 * rectInset,clipRectRight - 4 * rectInset,clipRectBottom - 4 * rectInset)}drawClippedRectangle(canvas)canvas.restore()}private fun drawCircularClippingExample(canvas: Canvas) {canvas.save()canvas.translate(columnOne, rowTwo)// Clears any lines and curves from the path but unlike reset(),// keeps the internal data structure for faster reuse.path.rewind()path.addCircle( //重疊的部分,以這部分為準circleRadius,clipRectBottom - circleRadius,circleRadius,Path.Direction.CCW //逆時針)// The method clipPath(path, Region.Op.DIFFERENCE) was deprecated in// API level 26. The recommended alternative method is// clipOutPath(Path), which is currently available in// API level 26 and higher.if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {canvas.clipPath(path, Region.Op.DIFFERENCE)} else {canvas.clipOutPath(path)}drawClippedRectangle(canvas)canvas.restore()}private fun drawIntersectionClippingExample(canvas: Canvas) {canvas.save()canvas.translate(columnTwo,rowTwo)canvas.clipRect(clipRectLeft,clipRectTop,clipRectRight - smallRectOffset,clipRectBottom - smallRectOffset)// The method clipRect(float, float, float, float, Region.Op// .INTERSECT) was deprecated in API level 26. The recommended// alternative method is clipRect(float, float, float, float), which// is currently available in API level 26 and higher.if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {canvas.clipRect(clipRectLeft + smallRectOffset,clipRectTop + smallRectOffset,clipRectRight,clipRectBottom,Region.Op.INTERSECT //交集- 相交剛好是綠色圓的部分, 其它的均為灰色,即不繪制???)} else {canvas.clipRect(clipRectLeft + smallRectOffset,clipRectTop + smallRectOffset,clipRectRight,clipRectBottom)}drawClippedRectangle(canvas)canvas.restore()}private fun drawCombinedClippingExample(canvas: Canvas) {canvas.save()canvas.translate(columnOne, rowThree)path.rewind()path.addCircle(clipRectLeft + rectInset + circleRadius,clipRectTop + circleRadius + rectInset,circleRadius,Path.Direction.CCW)path.addRect(clipRectRight / 2 - circleRadius,clipRectTop + circleRadius + rectInset,clipRectRight / 2 + circleRadius,clipRectBottom - rectInset,Path.Direction.CCW)canvas.clipPath(path) // 新的圓、正方形覆蓋原來的,這兩個形狀以外的部分為灰色drawClippedRectangle(canvas)canvas.restore()}private fun drawRoundedRectangleClippingExample(canvas: Canvas) {canvas.save()canvas.translate(columnTwo,rowThree)path.rewind()// rectF 區域, rx 半徑, ry 半徑, 方向path.addRoundRect(rectF,clipRectRight / 4,clipRectRight / 4, Path.Direction.CCW)canvas.clipPath(path) // 圓角邊框內的可見,其余的灰色drawClippedRectangle(canvas)canvas.restore()}//剪切可見的區域,其余為灰色private fun drawOutsideClippingExample(canvas: Canvas) {canvas.save()canvas.translate(columnOne,rowFour)canvas.clipRect(2 * rectInset,2 * rectInset,clipRectRight - 2 * rectInset,clipRectBottom - 2 * rectInset)drawClippedRectangle(canvas)canvas.restore()}// 文字private fun drawTranslatedTextExample(canvas: Canvas) {canvas.save()paint.color = Color.GREEN// Align the RIGHT side of the text with the origin.paint.textAlign = Paint.Align.LEFT// Apply transformation to canvas.canvas.translate(columnTwo, textRow)// Draw text.canvas.drawText(context.getString(R.string.translated),clipRectLeft, clipRectTop, paint)canvas.restore()}//Skewed 斜體private fun drawSkewedTextExample(canvas: Canvas) {canvas.save()paint.color = Color.YELLOWpaint.textAlign = Paint.Align.RIGHT// Position text.canvas.translate(columnTwo, textRow)// Apply skew transformation.canvas.skew(0.2f, 0.3f) //斜率 ,x ycanvas.drawText(context.getString(R.string.skewed),clipRectLeft, clipRectTop, paint)canvas.restore()}private fun drawQuickRejectExample(canvas: Canvas) {val inClipRectangle = RectF(clipRectRight / 2,clipRectBottom / 2,clipRectRight * 2,clipRectBottom * 2)val notInClipRectangle = RectF(RectF(clipRectRight+1,clipRectBottom+1,clipRectRight * 2,clipRectBottom * 2))canvas.save()canvas.translate(columnOne, rejectRow)canvas.clipRect(clipRectLeft,clipRectTop,clipRectRight,clipRectBottom)//如果完全不可見,則返回true, 只要有部分可見都返回falseif (canvas.quickReject(inClipRectangle, Canvas.EdgeType.AA)) {canvas.drawColor(Color.WHITE)}else {canvas.drawColor(Color.BLACK)canvas.drawRect(inClipRectangle, paint)}canvas.restore()} }

    其中,dimens.xml

    <?xml version="1.0" encoding="utf-8"?> <resources><dimen name="clipRectRight">90dp</dimen><dimen name="clipRectBottom">90dp</dimen><dimen name="clipRectTop">0dp</dimen><dimen name="clipRectLeft">0dp</dimen><dimen name="rectInset">8dp</dimen><dimen name="smallRectOffset">40dp</dimen><dimen name="circleRadius">30dp</dimen><dimen name="textOffset">20dp</dimen><dimen name="strokeWidth">4dp</dimen><dimen name="textSize">18sp</dimen> </resources>

    strings.xml

    <resources><string name="app_name">ClippingExample</string><string name="clipping">Clipping</string><string name="translated">translated text</string><string name="skewed">"Skewed and "</string> </resources> MainActivity.kt class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(ClippedView(this))} }

    ?

    總結

    以上是生活随笔為你收集整理的Android 自定义View 实例2_Clipping Canvas的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。