美文网首页
仿美团点赞动画

仿美团点赞动画

作者: 帝王鲨kingcp | 来源:发表于2017-10-31 17:23 被阅读0次
先上个GIF图,看一下点赞效果,这个效果也是比较常见的。下面的内容就是分析下这个点赞自定义View的实现和自己在实现过程中学习巩固的知识点。
dianzan.gif
首先我把整个点赞分成两个部分,一个是手指点亮的ThumbUpView,另一个是数字变化的ThumbUpNumberView。这样做的好处是点赞动画,和数字变化分开,到时候需要修改点赞动画时会方便一些。接下来一个个分析。

ThumbUpView

  1. 有下面两张图片组成,并且两张图片有重叠部分,所以决定让ThumbUpView继承FrameLayout。两个子View组合成点赞图片。
图1
图2
  1. 动画效果的实现,点亮效果是:图1和图2都是从无到有,仔细看甚至是先变大到原图120%后变小到原图100%的过程。取消点亮效果:图2消失,灰色手指和图1点亮一样出现。

思路分析完,看具体代码的实现

点赞图片组合的实现

//创建两个ImageView,添加到ThumbUpView中,在onLayout中设置两个ImageView的位置
 @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //在super.onLayout下面更改子view布局才有效果
        int count = getChildCount();
        for(int i = 0 ; i < count ; i++){
            View view = getChildAt(i);
            mChildViewLeft = view.getLeft();
            mChildViewTop = view.getTop();
            mChildViewRight = view.getRight();
            mChildViewBottom = view.getBottom();
            if(i == count - 1){//手指图片,整体往下
                view.layout(mChildViewLeft,mChildViewTop + 50,mChildViewRight,mChildViewBottom + 50);
            }else{
                view.layout(mChildViewLeft,mChildViewTop,mChildViewRight,mChildViewBottom);
            }
        }
    }

动画效果的实现

//将点击事件等交给GestureDetector处理   flag作为是否点赞的标记
mGestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                return true;//返回true,才能进入onSingleTapUp事件中
            }
            @Override
            public void onShowPress(MotionEvent e) {
            }
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                //单击
                Log.i(TAG, "onSingleTapUp: ");
                if(flag){//已经点赞,取消点赞
                    mShiningIv.setVisibility(INVISIBLE);
                    mLikeIv.setImageBitmap(mLikeUnselectedBp);
                    //时间0%时,变化值为0f
                    Keyframe keyframe1 = Keyframe.ofFloat(0,0f);
                    //时间80%时,变化值为1.2f
                    Keyframe keyframe2 = Keyframe.ofFloat(0.8f,1.2f);
                    //时间100%时,变化值为1.0f
                    Keyframe keyframe3 = Keyframe.ofFloat(1,1.0f);
                    PropertyValuesHolder pvh1 = PropertyValuesHolder.ofKeyframe("scaleX",keyframe1,keyframe2,keyframe3);
                    PropertyValuesHolder pvh2 = PropertyValuesHolder.ofKeyframe("scaleY",keyframe1,keyframe2,keyframe3);
                    ObjectAnimator.ofPropertyValuesHolder(mLikeIv,pvh1,pvh2).setDuration(200).start();
                    mThumbNumberView.cancelThumbUp();
                }else{//未点赞,进行点赞
                    mShiningIv.setVisibility(VISIBLE);
                    mLikeIv.setImageBitmap(mLikeSelectedBp);
                    //时间0%时,变化值为0f
                    Keyframe keyframe1 = Keyframe.ofFloat(0,0f);
                    //时间80%时,变化值为1.2f
                    Keyframe keyframe2 = Keyframe.ofFloat(0.8f,1.2f);
                    //时间100%时,变化值为1.0f
                    Keyframe keyframe3 = Keyframe.ofFloat(1,1.0f);
                    PropertyValuesHolder pvh1 = PropertyValuesHolder.ofKeyframe("scaleX",keyframe1,keyframe2,keyframe3);
                    PropertyValuesHolder pvh2 = PropertyValuesHolder.ofKeyframe("scaleY",keyframe1,keyframe2,keyframe3);
                    ObjectAnimator.ofPropertyValuesHolder(mLikeIv,pvh1,pvh2).setDuration(200).start();
                    ObjectAnimator.ofPropertyValuesHolder(mShiningIv,pvh1,pvh2).setDuration(200).start();
                    mThumbNumberView.thumbUp();
                }
                flag = !flag;
                return false;
            }
             ........
        });

ThumbUpNumberView

zan.gif
  1. 数值的变化只是改变变动部分。因此考虑把数值部分分为3类(String num[3]),不变部分num[0](在上图中是百位和十位上的99 ),原来变化部分num[1](原本个位上的8),后来的变化部分num[2](最后个位上的9)
  2. 数值的变化是一个滚动的动画效果,点赞的时候数值上翻,取消点赞的时候数值下翻。实现思路:设置OldoffsetY,offsetY来控制num[1],num[2]的一点时间内的变化,num[0]保持不动。
  3. 数值的变化中,num[1]总是从看的见到看不见,num[2]总是从看不见到看的见。这只要控制画笔颜色的ARGB值

思路分析完,看具体代码的实现

计算出数值的三个部分

  /**
     * 计算num不变及变化部分
     * @param newCount
     */
    private void calculateNum(int newCount) {
        mNum[0]=mNum[1]=mNum[2]="";
        String oldCountStr = String.valueOf(mCount);
        String newCountStr = String.valueOf(newCount);
        if(oldCountStr.length() != newCountStr.length()){//位数发生变化
            mNum[1] = oldCountStr;
            mNum[2] = newCountStr;
        }else{
            int length = oldCountStr.length();
            for(int i = 0 ; i < length ; i++){
                if(oldCountStr.charAt(i) == newCountStr.charAt(i)){//相同部分
                    mNum[0] += oldCountStr.charAt(i);
                }else{//不同部分
                    mNum[1] += oldCountStr.charAt(i);
                    mNum[2] += newCountStr.charAt(i);
                }
            }
        }
    }

滚动效果实现 mOffsetYFraction是自定义一个属性,用来获取一段时间中的变化率,需要实现get,set方法。在set方法中根据实际情况通过mOffsetYFraction计算出mOffsetY和mOldOffsetY来改变num[1],num[2]的位置。

    //文本颜色
    private static final int TEXT_DEFAULT_COLOR = Color.parseColor("#cccccc");
    private static final int TEXT_DEFAULT_END_COLOR = Color.parseColor("#00cccccc");
    //变化率
    private float mOffsetYFraction = 0.0f;

    public float getMOffsetYFraction() {
        return mOffsetYFraction;
    }
    //setMOffsetYFraction中M必须大写,否则不会调用
    public void setMOffsetYFraction(float mOffsetYFraction) {
        this.mOffsetYFraction = mOffsetYFraction;
        if(mOffsetYFraction < 0){//数字上翻[0,-1]
            mOffsetY = mOffsetYFraction * mTextHeight;
            mOldOffsetY = mOffsetYFraction * mTextHeight;
        }else{//数字下翻[0,1]
            mOffsetY = -2*mTextHeight + mOffsetYFraction*mTextHeight;
            mOldOffsetY = mOffsetYFraction * mTextHeight;
        }
        //在变化区间内会不断调用
        postInvalidate();
    }
  /**
     * 点赞动画
     */
    private void ThumbUpAnimator() {
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this,"mOffsetYFraction",0f,-1.0f);
        objectAnimator.setDuration(200);
        objectAnimator.start();
    }

    /**
     * 取消点赞动画
     */
    private void ThumbDownAnimator(){
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this,"mOffsetYFraction",0f,1.0f);
        objectAnimator.setDuration(200);
        objectAnimator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(TEXT_DEFAULT_COLOR);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        //通过FontMetrics获得文本宽度,单个字符宽度,文本高度
        float textWidth = paint.measureText(String.valueOf(mCount));
        float charWidth = textWidth / String.valueOf(mCount).length();
        mTextHeight = fontMetrics.bottom - fontMetrics.top;
        float fraction = Math.abs(mOffsetYFraction);
        //画不变部分
        canvas.drawText(mNum[0], 0 , mTextHeight, paint);
        //画变化的原来部分
        paint.setColor((Integer) evaluate(fraction, TEXT_DEFAULT_COLOR, TEXT_DEFAULT_END_COLOR));
        canvas.drawText(mNum[1], charWidth*mNum[0].length(), mTextHeight + mOldOffsetY, paint);
        //画变化的新的部分,将mNum[2]放在mNum[1]正下面
        paint.setColor((Integer) evaluate(fraction, TEXT_DEFAULT_END_COLOR, TEXT_DEFAULT_COLOR));
        canvas.drawText(mNum[2], charWidth*mNum[0].length(), mTextHeight*2 + mOffsetY, paint);
    }

字体颜色变化,通过evaluate方法

public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        float startA = ((startInt >> 24) & 0xff) / 255.0f;
        float startR = ((startInt >> 16) & 0xff) / 255.0f;
        float startG = ((startInt >> 8) & 0xff) / 255.0f;
        float startB = (startInt & 0xff) / 255.0f;

        int endInt = (Integer) endValue;
        float endA = ((endInt >> 24) & 0xff) / 255.0f;
        float endR = ((endInt >> 16) & 0xff) / 255.0f;
        float endG = ((endInt >> 8) & 0xff) / 255.0f;
        float endB = (endInt & 0xff) / 255.0f;

        // convert from sRGB to linear
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);

        // compute the interpolated color in linear space
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // convert back to sRGB in the [0..255] range
        a = a * 255.0f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

        return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
    }

相关文章

网友评论

      本文标题:仿美团点赞动画

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