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

2018-01-12  本文已影响0人  Noblel

前阵子又想回忆回忆自定义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);
    }
}

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

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

上一篇下一篇

猜你喜欢

热点阅读