美文网首页
自定义View之即刻点赞字节跳动

自定义View之即刻点赞字节跳动

作者: Noblel | 来源:发表于2018-01-12 15:35 被阅读0次

    前阵子又想回忆回忆自定义View,发现自己好久不写都忘记了,或者说根本没记住!(逃

    言归正传,通过HenCoder的学习,又对自定义View加深了下印象,自己再写一个简单的View。先看效果图:

    效果图

    看起来蛮有意思的,那就简单分析下。

    实现思路

    分析元素和效果:

    元素:有字(废话),有。。。没了
    效果:最后大于小于9的会加一位,并且往上走(其实都是假象)
    如果是9变成10 会全部往上走,同理1999也是一样会被2000顶掉

    效果实现:

    既然是动起来了,那我们就用动画吧,既然用动画了,那就用属性动画吧。
    属性动画用在哪呢?
    当然是最后变化的那个位置了,我们知道一旦属性动画开始可以让视图不断的执行onDraw方法,最后变成我们想要的位置,也就是9--》10 9在10上面一个看不见的地方,原本呢是10在9下面看不见的位置。

    那就开始写LikeView吧

    自定义属性:
    给个数字不过分吧。。
    给个字体颜色不过分吧。。
    给个字体大小也不能说过分吧。。

    重写onDraw方法(这里就拿1234--》1235变化来说明)

    1. 画1234,当然不能一个drawText画出来,一个drawText画123,再在后面drawText画4 给4赋上属性动画的改变量yOffset。
    2. 在1234的下面看不见的位置画一个5,当然是(4的x坐标) 和 (y + 整个视图的高度),y当然是基线了。
    3. 通过ObjectAnimator设置yOffset就可以让4和5同时移动了形成顶起的假象

    主要代码就在onDraw:

    @Override
    protected void onDraw(Canvas canvas) {
        //测量文字大小
        float likeNumStrWidth = mNumPaint.measureText(mLikeNumStr);
        float correctNumStrWidth = mNumPaint.measureText(mCorrectNumStr);
        //确定基线
        Paint.FontMetricsInt fontMetricsInt = mNumPaint.getFontMetricsInt();
        int centerX = getWidth() / 2;
        //文字高度的一半到基线的距离
        //top表示基线到文字最上面的位置的距离 是个负值 bottom为基线到最下面的距离,为正值
        int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
        int bastLine = getHeight() / 2 + dy;
        //index位置后的文字需要变化
        float index;
        //变化的text
        String changeText;
        //查找是哪个位置后都是需要改变,比如9999就会返回0,8就返回1,如果是1234返回-1,12399返回3.
        int theFirstNotNine = findTheFirstNotNine(mLikeNum);
        //每个字符的宽度
        float everyCharWidth = mNumPaint.measureText(mLikeNumStr) / mLikeNumStr.length();
        if (theFirstNotNine == NO_NINE) {
            //没有9证明只需要变化最后一位即可
            index = everyCharWidth * (mLikeNumStr.length() - 1);
            changeText = mCorrectNumStr.substring(mCorrectNumStr.length() - 1, mCorrectNumStr.length());
            canvas.drawText(mLikeNumStr, 0, mLikeNumStr.length() - 1, centerX - likeNumStrWidth / 2, bastLine, mNumPaint);
            canvas.drawText(mLikeNumStr, mLikeNumStr.length() - 1, mLikeNumStr.length(), centerX + index- likeNumStrWidth / 2, bastLine + mYOffset, mNumPaint);
        } else if (theFirstNotNine > 1) {
            //大于1 说明变化的地方在中间位置
            index = everyCharWidth * (theFirstNotNine - 1);
            //需要变化的文字
            changeText = mCorrectNumStr.substring(theFirstNotNine - 1, mCorrectNumStr.length());
            //画左半部分不变的部分
            canvas.drawText(mLikeNumStr, 0, theFirstNotNine - 1, centerX - likeNumStrWidth / 2, bastLine, mNumPaint);
            //画右边变化的部分
            canvas.drawText(mLikeNumStr, theFirstNotNine - 1, mLikeNumStr.length(), centerX + index - likeNumStrWidth / 2, bastLine + mYOffset, mNumPaint);
        } else {
            //说明全部需要变化,包括9999,1999,9
            index = 0;
            changeText = mCorrectNumStr;
            canvas.drawText(mLikeNumStr, centerX - likeNumStrWidth / 2, bastLine + mYOffset, mNumPaint);
        }
        //把变化的未显示的画出来,如果mYOffset改变为-getHeight()就会显示,原来的就会不显示
        canvas.drawText(changeText, centerX + index - correctNumStrWidth / 2, bastLine + mYOffset + getHeight(), mNumPaint);
    }
    

    次要代码就在onMeasure,解决wrap_content为match_parent情况。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int mayBeWidth = (int) (mNumPaint.measureText(mCorrectNumStr) + getPaddingLeft() + getPaddingRight());
        mWidth = (int) (mNumPaint.measureText(mLikeNumStr) + getPaddingLeft() + getPaddingRight());
        //这里有可能原来是9,加1后长度更长,做了下适配,选择更长的当作mWidth
        mWidth = Math.max(mWidth, mayBeWidth);
        mHeight = (int) (mNumSize + getPaddingTop() + getPaddingBottom());
        mWidth = Math.max(mWidth, getSuggestedMinimumWidth());
        if (widthMode == AT_MOST && heightMode == AT_MOST) {
            //设置默认宽高
            setMeasuredDimension(mWidth, mHeight);
        } else if (widthMode == AT_MOST) {
            setMeasuredDimension(mWidth, heightSize);
        } else if (heightMode == AT_MOST) {
            setMeasuredDimension(widthSize, mHeight);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
    

    主要提供思想。
    实际源码这里

    哪有写的不好的请帮我指正帮我提高。

    相关文章

      网友评论

          本文标题:自定义View之即刻点赞字节跳动

          本文链接:https://www.haomeiwen.com/subject/pyyfoxtx.html