模仿QQ运动item的界面

本文详细介绍了一个复杂的UI组件绘制过程,包括使用Canvas进行图形绘制、贝塞尔曲线应用、动画效果实现等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先按照老规矩,无图无真相嘛,先看看先:
这里写图片描述

是不是很像呢,那具体是实现是怎样的呢,即使概括的来说就是
1.计算各个变量的值(记得是会随整个View的大小变化而变化)。
2其次利用好canvas.translate()这个方法,计算好大小移动canvas的原点。
3最后就是调用api提供的各种方法画图就是了。
这么说是不是太过于简略了呢,好,现在就来看看那具体的吧。

首先看看xml有什么参数吧

 <com.example.jack.besselcurve.BesselCurveView
        android:id="@+id/besselCurveView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:layout_centerHorizontal="true"
        app:besselColor="@color/besselColor"
        app:besselColorText="@color/besselColorText"
        app:friendAverageStep="6752"
        app:averageStep="2603"
        app:champion="Jack"
        app:allStep="8765"
        app:time="17:26"
        app:ranking="15">
    </com.example.jack.besselcurve.BesselCurveView>

各参数对应的解释如下:

    //时间
    private String time;
    //所有步数
    private int allStop;
    //还有平均步数
    private int friendAverageStep;
    //平均步数
    private int averageStep;
    //排名
    private String ranking;
    //头像
    private Bitmap champion_icon;
    //冠军名字
    private String champion;

接着代码段初始化所有参数:

TypedArray mTypedArray=context.getTheme().obtainStyledAttributes(attrs,R.styleable.BesselCurveView,defStyleAttr,0);
        int numCount=mTypedArray.getIndexCount();
        for(int i=0;i<numCount;i++){
            int attr=mTypedArray.getIndex(i);
            switch(attr){
                case R.styleable.BesselCurveView_allStep:
                    allStop=mTypedArray.getInt(attr,0);
                    break;
                case R.styleable.BesselCurveView_averageStep:
                    averageStep=mTypedArray.getInt(attr,0);
                    break;
                case R.styleable.BesselCurveView_friendAverageStep:
                    friendAverageStep = mTypedArray.getInt(attr,0);
                    break;
                case R.styleable.BesselCurveView_time:
                    time=mTypedArray.getString(attr);
                    break;
                case R.styleable.BesselCurveView_ranking:
                    ranking=mTypedArray.getString(attr);
                    break;
                case R.styleable.BesselCurveView_champion:
                    champion=mTypedArray.getString(attr);
                    break;
                case R.styleable.BesselCurveView_besselColor:
                    mBesselCurveColor=mTypedArray.getColor(attr,Color.BLUE);
                    break;
                case R.styleable.BesselCurveView_besselColorText:
                    besselColorText=mTypedArray.getColor(attr,Color.GRAY);
                    break;
            }
        }

这些都是每个自定义都有的相当于模板,来初始化参数,都看的明白吧。
接下来也很简单,就是初始化画笔等变量,以便于后面看画图更简单:

public void initValue(){
        animSet=new AnimatorSet();
        //外圆的画笔
        mCirclePaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStyle(Paint.Style.STROKE);
        mCirclePaint.setStrokeWidth(radius/10);
        mCirclePaint.setStrokeJoin(Paint.Join.ROUND);
        mCirclePaint.setStrokeCap(Paint.Cap.ROUND);
        mCirclePaint.setAntiAlias(true);
        //中间的文字的画笔
        mCenterTextPaint=new Paint();
        mCenterTextPaint.setColor(mBesselCurveColor);
        mCenterTextPaint.setTextSize(radius/5);
        mCenterTextPaint.setAntiAlias(true);
        //除中间之外的文字的画笔
        mTextPaint=new Paint();
        mTextPaint.setAntiAlias(true);
        //最低下的矩形
        mBottomRectPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mBottomRectPaint.setColor(mBesselCurveColor);
        mBottomRectPaint.setAntiAlias(true);
        //虚线的画笔
        mDottedLinePaint = new Paint();
        mDottedLinePaint.setAntiAlias(true);
        mDottedLinePaint.setStyle(Paint.Style.STROKE);
        mDottedLinePaint.setStrokeWidth(2);
        mDottedLinePaint.setColor(mBesselCurveColor);
        mDottedLinePaint.setPathEffect(new DashPathEffect(new float[]{5,5},1));
        //画波浪线画笔
        WavylinesPaint=new Paint();
        WavylinesPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        WavylinesPaint.setColor(wavyColor);
        WavylinesPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        //虚线的画线
        mDottedLinePath=new Path();
        //画波浪线画线
        WavyLinePath=new Path();
        //底下更多的画线
        morePath=new Path();

        mWaveCount = (int) Math.round(widthView / mWaveLength + 1.5);
        marginBottomText=radius/4;
    }

好了,最重要的初始化都差不多了,现在就来画图(画画)吧
先贴出所有画的代码然后再逐一讲解吧:

  protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.translate(widthView/2,(heightView*((float)2/3))/2);

        //画内圆圈
        mCirclePaint.setColor(besselColorText);
        RectF mCircleRectF=new RectF(-radius,-radius,radius,radius);
        canvas.drawArc(mCircleRectF,120,300,false,mCirclePaint);

        //画外圆圈
        mCirclePaint.setColor(mBesselCurveColor);
        canvas.drawArc(mCircleRectF,120,mCircleNum,false,mCirclePaint);

        //画中间的文字
        Rect mCenterRect=new Rect();
        String tempAllStop=mCenterNum+"";
        mCenterTextPaint.getTextBounds(tempAllStop,0,tempAllStop.length(),mCenterRect);
        int halfWidthText=(mCenterRect.right-mCenterRect.left)/2;
        int halfHeightText=(mCenterRect.bottom-mCenterRect.top)/2;
        canvas.drawText(tempAllStop,-halfWidthText,halfHeightText,mCenterTextPaint);

        //画上边的文字
        mTextPaint.setColor(besselColorText);
        mTextPaint.setTextSize(radius/6);
        String tempFriendAverageStep=stringTemplate(R.string.besselTime,time);
        Rect mTopRect=new Rect();
        mTextPaint.getTextBounds(tempFriendAverageStep,0,tempFriendAverageStep.length(),mTopRect);
        int halfTopWidthText=(mTopRect.right-mTopRect.left)/2;
        canvas.drawText(tempFriendAverageStep,-halfTopWidthText,-(halfHeightText+marginText),mTextPaint);

        //画下边的文字
        String tempAverageStep=stringTemplate(R.string.friendAverageStep,friendAverageStep+"");
        Rect mBottomRect=new Rect();
        mTextPaint.getTextBounds(tempAverageStep,0,tempAverageStep.length(),mBottomRect);
        int halfBottomWidthText=(mBottomRect.right-mBottomRect.left)/2;
        int mBottomHeightText=(mBottomRect.bottom-mBottomRect.top);
        canvas.drawText(tempAverageStep,-halfBottomWidthText,mBottomHeightText+halfHeightText+marginText,mTextPaint);

        //画排名
        Rect mNumRect=new Rect();
        mCenterTextPaint.getTextBounds(ranking,0,ranking.length(),mNumRect);
        int halfNum=(mNumRect.right-mNumRect.left)/2;
        mCenterTextPaint.setTextSize(40);
        canvas.drawText(ranking,-halfNum,radius,mCenterTextPaint);
        String rankingLeft=getContext().getResources().getString(R.string.ranking_left);
        mTextPaint.getTextBounds(rankingLeft,0,rankingLeft.length(),mNumRect);
        canvas.drawText(rankingLeft,-halfNum-(mNumRect.right-mNumRect.left)/2-20,radius,mTextPaint);
        canvas.drawText(getContext().getResources().getString(R.string.ranking_right),halfNum+10,radius,mTextPaint);
        canvas.restore();

        //画最近七天和平均运动
        mTextPaint.setTextSize(radius/9);
        canvas.save();
        canvas.translate(0,heightView*((float)2/3));
        canvas.drawText(getContext().getResources().getString(R.string.nextSevenDay),marginLineChart,0,mTextPaint);
        Rect mPercentRect=new Rect();
        String mPercentText=stringTemplate(R.string.averageStep,averageStep+"");
        mTextPaint.getTextBounds(mPercentText,0,mPercentText.length(),mPercentRect);
        canvas.drawText(mPercentText,widthView-marginLineChart-(mPercentRect.right-mPercentRect.left),0,mTextPaint);

        //画虚线
        mDottedLinePath.moveTo(marginLineChart,marginBottomText);
        mDottedLinePath.lineTo(widthView-marginLineChart,marginBottomText);
        canvas.drawPath(mDottedLinePath,mDottedLinePaint);

        //画7天数据柱状图
        mTextPaint.setTextSize(radius/9);
        int lineWidth=(widthView-marginLineChart*2)/8;
        mCalendar.setTime(new Date());
        RectF mRecf=null;
        if(mListStep.size()>0){
            for(int i=mListStep.size();i>=1;i--){
                if(mListStep.get(i-1)!=0){
                    int startX=marginLineChart+lineWidth*i-radius/23;
                    int endX=marginLineChart+lineWidth*i+radius/23;
                    if(mListStep.get(i-1)>mStandardStop){
                        //达标
                        mTextPaint.setColor(mBesselCurveColor);
                        int exceed=mListStep.get(i-1)-mStandardStop;
                        float standard=(float)(mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop)));
                        mRecf=new RectF(startX,marginBottomText-(standard>mCircleRectHeight?mCircleRectHeight:standard)
                                    ,endX,marginBottomText+mCircleRectHeight);
                        canvas.drawRoundRect(mRecf,50,50,mTextPaint);
                    }else{
                        //不达标
                        mTextPaint.setColor(besselColorText);
                        float noStandard=(float)(mCircleRectHeight*Double.valueOf(mListStep.get(i-1)/Double.valueOf(mStandardStop)));
                        mRecf=new RectF(startX,marginBottomText,endX,marginBottomText+(
                                noStandard>mCircleRectHeight?mCircleRectHeight:noStandard));
                        canvas.drawRoundRect(mRecf,50,50,mTextPaint);
                    }
                }

                //画底下的日期
                mTextPaint.setColor(besselColorText);
                mCalendar.set(Calendar.DAY_OF_MONTH,mCalendar.get(Calendar.DAY_OF_MONTH)-1);
                Rect rect =new Rect();
                String number=stringTemplate(R.string.day,mCalendar.get(Calendar.DAY_OF_MONTH)+"");
                mTextPaint.getTextBounds(number,0,number.length(),rect);
                canvas.drawText(number,(marginLineChart+lineWidth*i)-(rect.right-rect.left)/2,marginBottomText+70,mTextPaint);
            }
        }
        canvas.restore();

        //画波浪图形
        canvas.save();
        float mWavyHeight=heightView*((float)4/5)+50;
        canvas.translate(0,mWavyHeight);
        WavyLinePath.reset();
        WavyLinePath.moveTo(-mWaveLength+ mOffset,0);
        int wHeight=radius/5;
        for(int i=0;i<mWaveCount;i++){
            WavyLinePath.quadTo((-mWaveLength*3/4)+(i*mWaveLength)+mOffset,wHeight,(-mWaveLength/2)+(i*mWaveLength)+mOffset,0);
            WavyLinePath.quadTo((-mWaveLength/4)+(i * mWaveLength)+mOffset,-wHeight,i*mWaveLength+mOffset,0);
        }
        WavyLinePath.lineTo(widthView,heightView-mWavyHeight);
        WavyLinePath.lineTo(0,heightView-mWavyHeight);
        WavyLinePath.close();
        canvas.drawPath(WavyLinePath,WavylinesPaint);
        canvas.restore();

        //画最低的信息
        float removeHeight=mWavyHeight+(radius/5);
        canvas.translate(0,removeHeight);
        float rectHeight=heightView-removeHeight;

        //画底下的矩形
        RectF rect = new RectF(0,0,widthView,rectHeight);
        canvas.drawRect(rect,mBottomRectPaint);

        //画头像
        int bitmap_icon_x=radius/5;
        float centerHeight=rectHeight/2;
        Bitmap bitmap_icon=getRoundCornerImage(champion_icon,50,radius/5,radius/5);
        canvas.drawBitmap(bitmap_icon,bitmap_icon_x,centerHeight-bitmap_icon.getHeight()/2,null);
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTextSize(radius/8);

        //画冠军文字
        int champion_x=radius/2;
        Rect mNameRect=new Rect();
        String championMame=stringTemplate(R.string.champion,champion);
        mTextPaint.getTextBounds(championMame,0,championMame.length(),mNameRect);
        canvas.drawText(championMame,champion_x,(rectHeight+(mNameRect.bottom-mNameRect.top))/2,mTextPaint);

        //画查看
        String look=getContext().getResources().getString(R.string.check);
        mTextPaint.getTextBounds(look,0,look.length(),mNameRect);
        canvas.drawText(look,widthView-(radius*(float)2/3),(rectHeight+(mNameRect.bottom-mNameRect.top))/2,mTextPaint);

        //画更多图像
        float morePoint=(radius*(float)2/3)/2;
        canvas.drawLine(widthView-morePoint,centerHeight-(mNameRect.bottom-mNameRect.top)/2,
                widthView-morePoint+15,centerHeight,mTextPaint);
        canvas.drawLine(widthView-morePoint+15,centerHeight,widthView-morePoint,
                centerHeight+(mNameRect.bottom-mNameRect.top)/2,mTextPaint);

    }

代码是不是有点多呢,没办法画的东西本身就有点多了。好了刚开始我说要移动canvas的原点是不是,你看刚开始就移动了吧:

super.onDraw(canvas);
canvas.save();
canvas.translate(widthView/2,(heightView*((float)2/3))/2);

1、移动原点到整个圆弧的中心,其中widthView是整个view的宽,heightView是整个view的高,如下图:
这里写图片描述
就在上图的蓝色点就是现在的原点。
然后在这原点里画圆弧呗,代码如下

 //画内圆圈
 mCirclePaint.setColor(besselColorText);
 RectF mCircleRectF=new RectF(-radius,-radius,radius,radius);
 canvas.drawArc(mCircleRectF,120,300,false,mCirclePaint);
 //画外圆圈
 mCirclePaint.setColor(mBesselCurveColor);
 canvas.drawArc(mCircleRectF,120,mCircleNum,false,mCirclePaint);

mCircleNum是为了实现动画效果的,这后面会讲,这样圆弧就画完了。效果也是如上图。

2.在中心点再画今天的走的总路程,代码如下:

  //画中间的文字
  Rect mCenterRect=new Rect();
  String tempAllStop=mCenterNum+"";
  mCenterTextPaint.getTextBounds(tempAllStop,0,tempAllStop.length(),mCenterRect);
  int halfWidthText=(mCenterRect.right-mCenterRect.left)/2;
  int halfHeightText=(mCenterRect.bottom-mCenterRect.top)/2;
  canvas.drawText(tempAllStop,-halfWidthText,halfHeightText,mCenterTextPaint);

基本的实现思路是用Rect在这个类计算出你要画文字的大小,然后在原点画,不过,
记得这里的x,y点是在原点的左下,具体详解看这里写链接内容

接这就是画时间和好友平均步数,其实实现原理也是一样的,只不过在上面的高度是

 canvas.drawText(tempFriendAverageStep,-halfTopWidthText,-(halfHeightText+marginText),mTextPaint);

是中心总步数高度的一半再加间隔,而下面的是:

canvas.drawText(tempAverageStep,-halfBottomWidthText,mBottomHeightText+halfHeightText+marginText,mTextPaint);

是下面文字总的高度再加上中心总步数高度的一半再加间隔。现在效果如下图:
这里写图片描述

接着就是画排名,首先还是套路:

Rect mNumRect=new Rect();
mCenterTextPaint.getTextBounds(ranking,0,ranking.length(),mNumRect);
int halfNum=(mNumRect.right-mNumRect.left)/2;
mCenterTextPaint.setTextSize(40);
canvas.drawText(ranking,-halfNum,radius,mCenterTextPaint);

计算出排名文字的大小,然后在中心原点x轴为排名文字的一半,y轴问为半径画出排名,效果图如下:
这里写图片描述
接着就在排名的两端画文字就行了,带代码如下:

        String rankingLeft=getContext().getResources().getString(R.string.ranking_left);
        mTextPaint.getTextBounds(rankingLeft,0,rankingLeft.length(),mNumRect);
        canvas.drawText(rankingLeft,-halfNum-(mNumRect.right-mNumRect.left)/2-20,radius,mTextPaint);
        canvas.drawText(getContext().getResources().getString(R.string.ranking_right),halfNum+10,radius,mTextPaint);

思路还是一样,就不说了。此时效果
这里写图片描述

画底下柱状图是,首先用canvas.restore();恢复原点到(0,0)的状态,再用canvas.translate(0,heightView*((float)2/3));把原点移动到圆弧的下面,接着又可以继续画,实现思路和前面一样:

    //画最近七天和平均运动
        mTextPaint.setTextSize(radius/9);
        canvas.save();
        canvas.translate(0,heightView*((float)2/3));
        canvas.drawText(getContext().getResources().getString(R.string.nextSevenDay),marginLineChart,0,mTextPaint);
        Rect mPercentRect=new Rect();
        String mPercentText=stringTemplate(R.string.averageStep,averageStep+"");
        mTextPaint.getTextBounds(mPercentText,0,mPercentText.length(),mPercentRect);
        canvas.drawText(mPercentText,widthView-marginLineChart-(mPercentRect.right-mPercentRect.left),0,mTextPaint);

        //画虚线
        mDottedLinePath.moveTo(marginLineChart,marginBottomText);
        mDottedLinePath.lineTo(widthView-marginLineChart,marginBottomText);
        canvas.drawPath(mDottedLinePath,mDottedLinePaint);

此时效果如下:
这里写图片描述

接下来画柱状图,首先int lineWidth=(widthView-marginLineChart*2)/8;计算出每个点之间的间隔
这里写图片描述

    if(mListStep.size()>0){
            for(int i=mListStep.size();i>=1;i--){
                if(mListStep.get(i-1)!=0){
                    //计算出起始点X和终点X的值
                    int startX=marginLineChart+lineWidth*i-radius/23;
                    int endX=marginLineChart+lineWidth*i+radius/23;
                    if(mListStep.get(i-1)>mStandardStop){
                        //达标
                       mTextPaint.setColor(mBesselCurveColor);
                       //超出的部分 
                        int exceed=mListStep.get(i-1)-mStandardStop;
                        //算出柱体大小
                        float standard=(float)(mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop)));
                        mRecf=new RectF(startX,marginBottomText-(standard>mCircleRectHeight?mCircleRectHeight:standard)
                                    ,endX,marginBottomText+mCircleRectHeight);
                        canvas.drawRoundRect(mRecf,50,50,mTextPaint);
                    }else{
                        //不达标
                        mTextPaint.setColor(besselColorText);
                        //算出不达标柱体的大小
                        float noStandard=(float)(mCircleRectHeight*Double.valueOf(mListStep.get(i-1)/Double.valueOf(mStandardStop)));
                        mRecf=new RectF(startX,marginBottomText,endX,marginBottomText+(
                                noStandard>mCircleRectHeight?mCircleRectHeight:noStandard));
                        canvas.drawRoundRect(mRecf,50,50,mTextPaint);
                    }
                }

                //画底下的日期
                mTextPaint.setColor(besselColorText);
                mCalendar.set(Calendar.DAY_OF_MONTH,mCalendar.get(Calendar.DAY_OF_MONTH)-1);
                Rect rect =new Rect();
                String number=stringTemplate(R.string.day,mCalendar.get(Calendar.DAY_OF_MONTH)+"");
                mTextPaint.getTextBounds(number,0,number.length(),rect);
                canvas.drawText(number,(marginLineChart+lineWidth*i)-(rect.right-rect.left)/2,marginBottomText+70,mTextPaint);
            }
        }

mStandardStop是达标的数据,当数据小于mStandardStop就是不达标,所以柱状图就要画在虚线的下面,mCircleRectHeight是柱状图一半的高
float standard=(float)(mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop)));这句代码是计算出下面圆柱体的具体大小,noStandard>mCircleRectHeight?mCircleRectHeight:noStandard当,但柱状图大于mCircleRectHeight时就用mCircleRectHeight不然就根据计算的数值来。
当数据大于mStandardStop时,int exceed=mListStep.get(i-1)-mStandardStop;float standard=(float)(mCircleRectHeight*Double.valueOf(exceed/Double.valueOf(mStandardStop)));exceed是计算出超出的部分,再拿超出的部分算出具体的大小,剩下的和小于的一样,当standard大于最大的mCircleRectHeight是就用mCircleRectHeight否则就用standard。
底下日期是用Calendar得到前7天的日期再循环的画上去,思路和上面一样不再赘述。此时效果如下:
这里写图片描述

接下来是画波浪,画波浪是用了贝塞尔曲线的方法画的,如果不懂贝塞尔曲线请参考这里写链接内容,这也是我学贝塞尔曲线参考的内容。首先我们又把canvas恢复到原点canvas.restore();再用
float mWavyHeight=heightView*((float)4/5)+50;
canvas.translate(0,mWavyHeight);
移动这个位置,是为了适配。

        WavyLinePath.reset();
        WavyLinePath.moveTo(-mWaveLength+ mOffset,0);
        int wHeight=radius/5;
        for(int i=0;i<mWaveCount;i++){
            WavyLinePath.quadTo((-mWaveLength*3/4)+(i*mWaveLength)+mOffset,wHeight,(-mWaveLength/2)+(i*mWaveLength)+mOffset,0);
            WavyLinePath.quadTo((-mWaveLength/4)+(i * mWaveLength)+mOffset,-wHeight,i*mWaveLength+mOffset,0);
        }
        WavyLinePath.lineTo(widthView,heightView-mWavyHeight);
        WavyLinePath.lineTo(0,heightView-mWavyHeight);
        WavyLinePath.close();
        canvas.drawPath(WavyLinePath,WavylinesPaint);

WavyLinePath.quadTo就是贝塞尔曲线调的方法,for循环几次使之形成波浪图形,记得一样要WavyLinePath.lineTo().不让会出现底下有些地方会画不到。原理是向上定一个控制点有向下定一个控制点使之形成一个sin函数图形。具体请学贝塞尔曲线。此时效果图:
这里写图片描述

最后就是画底下的矩形和头像和文字了。最值得讲的是头像我一开始的设想的传Url的,不过这样子又要做网络方面的代码工作,这样子会破怀类的功能单一性原则,所以最后我实在外部传一个位图,在位图进行处理使其圆角。剩下的只是画文字而已,上面已经讲够多了,就不在讲了。

对了,最后还有一个刚开始的动画效果。

public void startAnimator(){
        ValueAnimator mCircleAminator=ValueAnimator.ofFloat(0f,300f);
        mCircleAminator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCircleNum=(float)animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator mCenterText=ValueAnimator.ofInt(0,allStop);
        mCenterText.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCenterNum=(int)animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator mWavyAnimator = ValueAnimator.ofInt(0, mWaveLength);
        mWavyAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mOffset = (int) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animSet.setDuration(2000);
        animSet.playTogether(mCircleAminator,mCenterText,mWavyAnimator);
        animSet.start();
    }

    //字符串拼接
    public String stringTemplate(int template,String content){
        return String.format(getContext().getResources().getString(template),content);
    }

其实也简单通过设置ValueAnimator让它在规定的时间内产生数值的变化,再调用postInvalidate().对View的界面进行刷新即可实现动画效果。

最后给源码好好研究吧源码只有好好看源码才能学到更多东西。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值