扣丁書屋

Android 自定義View—月有陰晴圓缺

預覽

實現

先放個橢圓的圖,等會會用上輔助講解實現原理

如果這個 Major axis 的長度等于 Minor axis 的長度,就是一個正圓(知識點還給數學老師了,忘了這兩個軸叫什么了 QAQ )

現在發揮一下想象力,固定 Major axis 修改 Minor axis 的值,這就是一個變化的橢圓,再配合一個半圓,合并后的圖形,對一個正圓的遮擋,是不是就變成月有陰晴圓缺了?

哈哈哈~接下來就是核心代碼和注釋了。應該都能看懂吧。

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    // 黑色背景上面畫了個橙色的正圓
    canvas.drawColor(ContextCompat.getColor(context!!, android.R.color.black))
    val rectF = RectF(0f, 0f, width.toFloat(), height.toFloat())
    paint.color = ContextCompat.getColor(context!!, android.R.color.holo_orange_light)
    val radius = min(width, height) * 0.3f
    canvas.drawCircle(rectF.centerX(), rectF.centerY(), radius, paint)

    val c = canvas.saveLayer(
        RectF(0f, 0f, width.toFloat(), height.toFloat()),
        null,
        Canvas.ALL_SAVE_FLAG
    )
    paint.isDither = true
    paint.xfermode =  PorterDuffXfermode(PorterDuff.Mode.DST_OVER)

    // 下面的這些計算跟mPhase的改變方式有關
    // 首先mPhase 是由CountDownTimer進行修改的 
    // 創建一個矩形,固定中心在屏幕中間
    val rectFOval = when {
        mPhase > 150 -> {
            // 這里橢圓的 `Minor axis` 在變小   眉月 -> 上弦月
            RectF(
                rectF.centerX() - radius * (mPhase - 150) / 150,
                rectF.centerY() - radius,
                rectF.centerX() + radius * (mPhase - 150) / 150,
                rectF.centerY() + radius
            )
        }
        mPhase < 150 -> {
            // 這里橢圓的 `Minor axis` 在變大。上弦月 -> 盈凸月
            RectF(
                rectF.centerX() - (radius - radius * mPhase / 150),
                rectF.centerY() - radius,
                rectF.centerX() + (radius - radius * mPhase / 150),
                rectF.centerY() + radius
            )
        }
        else -> {
            null
        }
    }

    val rectFCircle = RectF(
        rectF.centerX() - radius,
        rectF.centerY() - radius,
        rectF.centerX() + radius,
        rectF.centerY() + radius

    )

    paint.color = ContextCompat.getColor(context!!, android.R.color.black)

    when {
        mPhase == 150 -> {
            if (rectFOval != null) {
                canvas.drawOval(rectFOval, paint)
            }
            canvas.drawArc(rectFCircle, 90f, 180f, false, paint)
        }
        mPhase == 0 -> {
            // 滿月,不繪制遮擋的部分
        }
        mPhase < 150 -> {
            // 先畫半圓,再畫橢圓
            canvas.drawArc(rectFCircle, 90f, 180f, false, paint)
            // 當 'Minor axis' 的長度減少 0, 然后再增加。月相的變化是 眉月 -> 上弦月 -> 盈凸月
            paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)
            canvas.drawOval(rectFOval!!, paint)
        }
        else -> {
            canvas.drawOval(rectFOval!!, paint)
            canvas.drawArc(rectFCircle, 90f, 180f, false, paint)
        }
    }
    paint.xfermode = null
    canvas.restoreToCount(c)
    Log.d("LunarPhase", "mRotate=$mRotate")
    // Rotate the canvas. For recording preview.
    canvas.rotate(mRotate.toFloat())
}

文中用到的 PorterDuffXfermode,再補充一個圖,半圓和橢圓的關系和月相變化的關系:

這個圖的偽代碼

drawColor() // CLEAR

drawCiricle() // 畫[圓],DST

paint.xfermode = ***

drawRect() // 畫[方],SRC

在這里用上了兩個

PorterDuff.Mode.DST_OVER

從圖中上可以看到,DST_OVER 表現的結果是 合并之后的圖形,圓 在上。換到我們的代碼里面,即 半圓橢圓 的合并起來,再配合我們的背景,即實現了眉月的變化。

PorterDuff.Mode.DST_OUT

從圖中上可以看到,DST_OUT 表現的結是 侵蝕,只顯示侵蝕后的部分 。換到我們的代碼里面,即 橢圓半圓 侵蝕了,再配合我們的背景,即實現了盈凸月的變化。因為是侵蝕關系,這里的繪制的先后順序是很重要的,先畫 半圓 ,就可以保留 半圓 被侵蝕的部分。

在貼下效果圖:

總結

寫代碼真的很快樂~~有些知識點,放下一段時間再拿起來說不定就有新的理解了。即溫故而知新。


https://mp.weixin.qq.com/s/5ENWaMpzgE7MPWcCMjwffg

最多閱讀

簡化Android的UI開發 2年以前  |  515113次閱讀
Android 深色模式適配原理分析 1年以前  |  26416次閱讀
Android 樣式系統 | 主題背景覆蓋 1年以前  |  7953次閱讀
Android Studio 生成so文件 及調用 1年以前  |  5587次閱讀
30分鐘搭建一個android的私有Maven倉庫 3年以前  |  4751次閱讀
Android設計與開發工作流 2年以前  |  4413次閱讀
Google Enjarify:可代替dex2jar的dex反編譯 3年以前  |  4397次閱讀
Android多渠道打包工具:apptools 3年以前  |  4028次閱讀
移動端常見崩潰指標 2年以前  |  4014次閱讀
Google Java編程風格規范(中文版) 3年以前  |  3942次閱讀
Android-模塊化-面向接口編程 1年以前  |  3857次閱讀
Android內存異常機制(用戶空間)_NE 1年以前  |  3824次閱讀
Android UI基本技術點 3年以前  |  3790次閱讀
Android死鎖初探 2年以前  |  3734次閱讀

手機掃碼閱讀
18禁止午夜福利体验区,人与动人物xxxx毛片人与狍,色男人窝网站聚色窝
<蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>