An imitation custom view eclipse

I, EDITORIAL words

Effect as shown above, the author at the time of the lunch break, re-chase again Detective Di Renjie II, conspired to use eclipse snake spirit, cited Luo Wu Zhou water subvert the boat. Solar eclipse comes, dark world, after the eclipse of all things bright reply. After reading a thought, or I have not got to see a solar eclipse effect, then, there is this article.

Second, the analysis Animation

First, there is a circle, a name, called the Sun (Sun), Moon (Moon) slowly slip from the Sun, and as the two circles overlap, the background becomes dark, when the complete coincidence of the maximum depth, Sun Moon slowly and then separated, separated when the background color faded, and finally restitution, logo appear. There are two technical point, the first control is the background color; only the second round is the Moon and Sun overlapped portion is visible, the rest is not visible, so that eclipse is realistic.

Third, the painting (onDraw)

//draw太阳
        canvas?.drawCircle(centerX.toFloat(), centerY.toFloat(), mSunR.toFloat(), mSunPaint)

First, draw a circle as the sun. So the moon is not drawing a small circle in the same way? Well, not exactly, if the same way, a circle drawn on the back cover in the moon, the real eclipse because a large brightness of the sun, only to see the moon on the sun with the naked eye, so we use this stuff to PorterDuffXfermode ,As follows:

        xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)

This mode has a wide variety, this is not the focus of this article, will not be discussed, probably means that only overlap partially visible. Videos moon section as shown below


        //draw月亮
        mSunPaint.color = mMoonColor

        mSunPaint.xfermode = xfermode
        canvas?.drawCircle(mMoonX.toFloat(), centerY.toFloat(), mMoonR.toFloat(), mSunPaint)
        mSunPaint.xfermode = null

Next draw logo, to be the first shot after the draw in the Sun and Moon, and before the moon in the painting. The complete code portion so as onDraw

override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        mSunPaint.color = mSunColor
        //draw太阳
        canvas?.drawCircle(centerX.toFloat(), centerY.toFloat(), mSunR.toFloat(), mSunPaint)

        if (isLogoShow) {
            mLogoPaint.xfermode = xfermode
            canvas?.drawBitmap(mLogoBitmap, mLogoBitmapSrcRect, mLogoBitmapDesRect, mLogoPaint)
            mLogoPaint.xfermode = null
        }
        //draw月亮
        mSunPaint.color = mMoonColor

        mSunPaint.xfermode = xfermode
        canvas?.drawCircle(mMoonX.toFloat(), centerY.toFloat(), mMoonR.toFloat(), mSunPaint)
        mSunPaint.xfermode = null

    }

Elements are drawn well, it is to let them take over where to move, I use a handler implementation. The first is to enter the animation, every change of the X coordinate Moon

 MSG_IN -> {
                if (mMoonX < centerX) {
                    mMoonX += mMoonXOffset
                    invalidate()
                    it.target.sendEmptyMessageDelayed(MSG_IN, mAnimationSpeed)
                } else if (kotlin.math.abs(mMoonX - centerX) <= mMoonXOffset) {
                    isLogoShow = true
                    invalidate()
                    it.target.sendEmptyMessageDelayed(MSG_OUT, 500)
                }
                progressOffset = txfloat((mMoonX - mMoonStartX), (4 * mSunR))

            }

Exit and entry animation animation also like to do but to draw the logo, opacity of the brush gradually increases, so will not appear in the logo too obtrusive.

MSG_OUT -> {
                if (mMoonX - centerX < 2 * mSunR) {
                    mMoonX += mMoonXOffset
                    var tempAlpha = 255 * (mMoonX - centerX) / (2 * mSunR)
                    if (tempAlpha > mLogoPaint.alpha) {
                        if (tempAlpha > 255) {
                            tempAlpha = 255
                        }
                        mLogoPaint.alpha = tempAlpha
                    }
                    invalidate()
                    it.target.sendEmptyMessageDelayed(MSG_OUT, mAnimationSpeed)
                }
                progressOffset = txfloat((mMoonX - mMoonStartX), (4 * mSunR))

            }

Then there is the background color changes here I will give you a method of calculating color.

/**
     * 根据fraction值来计算当前的颜色。
     */
    private fun getCurrentColor(fraction: Float, startColor: Int, endColor: Int): Int {
        val redCurrent: Int
        val blueCurrent: Int
        val greenCurrent: Int
        val alphaCurrent: Int
        val redStart = Color.red(startColor)
        val blueStart = Color.blue(startColor)
        val greenStart = Color.green(startColor)
        val alphaStart = Color.alpha(startColor)
        val redEnd = Color.red(endColor)
        val blueEnd = Color.blue(endColor)
        val greenEnd = Color.green(endColor)
        val alphaEnd = Color.alpha(endColor)
        val redDifference = redEnd - redStart
        val blueDifference = blueEnd - blueStart
        val greenDifference = greenEnd - greenStart
        val alphaDifference = alphaEnd - alphaStart
        redCurrent = (redStart + fraction * redDifference).toInt()
        blueCurrent = (blueStart + fraction * blueDifference).toInt()
        greenCurrent = (greenStart + fraction * greenDifference).toInt()
        alphaCurrent = (alphaStart + fraction * alphaDifference).toInt()
        return Color.argb(alphaCurrent, redCurrent, greenCurrent, blueCurrent)
    }

We need a callback background out through the listener, so that the parent layout view to achieve. why? Because if we drew a background in internal control, the painting method by xfermode Moon in the background over the entire visible (we asked Moon eclipse was visible only in part overlap with Sun)

   if (it.what == MSG_IN || it.what == MSG_OUT) {
            val color = if (progressOffset * 2 > 1) {
                getCurrentColor(2 - progressOffset * 2, mBgStartColor, mBgEndColor)
            } else {
                getCurrentColor(progressOffset * 2, mBgStartColor, mBgEndColor)
            }
            eclipseListener?.onColor(color)
        }

In this way, we eclipse is complete.

Fourth, the use

Add it in your root build.gradle at the end of repositories:

	allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}

Add the dependency

	dependencies {
	        implementation 'com.github.cqcby1994:MyView:1.2.1'
	}
<com.chen.eclipseview.EclipseLogo
        android:id="@+id/eclipse_view"
        app:logoSize="large"
        app:speed="middle"
        app:sunColor="@android:color/white"
        app:moonColor="#279536"
        app:endBackgroundColor="#279536"
        app:startBackgroundColor="@android:color/white"
        app:logoSrc="@mipmap/wechat"
        android:layout_width="200dp"
        android:layout_height="200dp"
 />

 You can define their own parameters of velocity (speed), logo, logo size, color and so on.

github: Point me to see

If you feel good, Dodo little hands, encourage encouragement to the author a star, if you had wanted to achieve and I are willing to exchange controls, you can leave a comment below, thank you.

Published 15 original articles · won praise 10 · views 10000 +

Guess you like

Origin blog.csdn.net/qwe749082787/article/details/105372683