Material Design学习之 ProgreesBar

tc20151681 8年前

来自: http://blog.csdn.net/ddwhan0123/article/details/50595766


转载奇怪注明出处:王亟亟的大牛之路

继续我们Material Design的内容,这一篇讲的是进度条,上一篇是Switch地址如下:http://blog.csdn.net/ddwhan0123/article/details/50592579


进度和动态

在用户可以查看并与内容进行交互之前,尽可能地减少视觉上的变化,尽量使应用加载过程令人愉快。每次操作只能由一个活动指示器呈现,例如,对于刷新操作,你不能即用刷新条,又用动态圆圈来指示。

指示器类型
在操作中,对于完成部分可以确定的情况下,使用确定的指示器,他们能让用户对某个操作所需要的时间有个快速的了解。

在操作中,对于完成部分不确定的情况下,用户需要等待一定的时间,无需告知后用户台的情况以及所需时间,这时可以使用不确定的指示器。

指示器的类型有两种:线形进度指示器和圆形进度指示器。你可以使用其中任何一项来指示确定性和不确定性的操作。

线形进度指示器

线形进度指示器应始终从 0% 到 100% 显示,绝不能从高到低反着来。如果一个队列里有多个正在进行的操作,使用一个进度指示器来指示整体的所需要等待的时间。这样,当指示器达到 100% 时,它不会返回到0%再重新开始。

线形进度条应该放置在页眉或某块区域的边缘。

贴2个官方的演示:

条状的
这里写图片描述

环状的

这里写图片描述

例子的实现
这里写图片描述

高防高仿,包结构:

这里写图片描述

OK,我们来看下代码(解释就解释 环状的,条状的比较简单)!

 final static String ANDROIDXML = "http://schemas.android.com/apk/res/android";        int backgroundColor = Color.parseColor("#1E88E5");          public ProgressBarCircularIndeterminate(Context context, AttributeSet attrs) {          super(context, attrs);          setAttributes(attrs);        }

21-30,构造函数以及调用初始化的方法

  protected void setAttributes(AttributeSet attrs){            setMinimumHeight(Utils.dpToPx(32, getResources()));          setMinimumWidth(Utils.dpToPx(32, getResources()));            //Set background Color          // Color by resource          int bacgroundColor = attrs.getAttributeResourceValue(ANDROIDXML,"background",-1);          if(bacgroundColor != -1){              setBackgroundColor(getResources().getColor(bacgroundColor));          }else{              // Color by hexadecimal              int background = attrs.getAttributeIntValue(ANDROIDXML, "background", -1);              if (background != -1)                  setBackgroundColor(background);              else                  setBackgroundColor(Color.parseColor("#1E88E5"));          }            setMinimumHeight(Utils.dpToPx(3, getResources()));          }

33-55行,获取xml的参数设置颜色,设置大小的最小值。

    protected int makePressColor(){          int r = (this.backgroundColor >> 16) & 0xFF;          int g = (this.backgroundColor >> 8) & 0xFF;          int b = (this.backgroundColor >> 0) & 0xFF;  // r = (r+90 > 245) ? 245 : r+90;  // g = (g+90 > 245) ? 245 : g+90;  // b = (b+90 > 245) ? 245 : b+90;          return Color.argb(128,r, g, b);      }

61-79行,颜色渐变的实现,第一次出现时调用。

 @Override      protected void onDraw(Canvas canvas) {          super.onDraw(canvas);          if(firstAnimationOver == false)              drawFirstAnimation(canvas);          if(cont > 0)              drawSecondAnimation(canvas);          invalidate();        }

72-81行,具体绘制的操作,因为要判断是否第一次,所以调用了2种不同的方法,我们一个个看。

    float radius1 = 0;      float radius2 = 0;      int cont = 0;      boolean firstAnimationOver = false;      /** * Draw first animation of view * @param canvas */      private void drawFirstAnimation(Canvas canvas){          if(radius1 < getWidth()/2){              Paint paint = new Paint();              paint.setAntiAlias(true);              paint.setColor(makePressColor());              radius1 = (radius1 >= getWidth()/2)? (float)getWidth()/2 : radius1+1;              canvas.drawCircle(getWidth()/2, getHeight()/2, radius1, paint);          }else{              Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);              Canvas temp = new Canvas(bitmap);              Paint paint = new Paint();              paint.setAntiAlias(true);              paint.setColor(makePressColor());              temp.drawCircle(getWidth()/2, getHeight()/2, getHeight()/2, paint);              Paint transparentPaint = new Paint();              transparentPaint.setAntiAlias(true);              transparentPaint.setColor(getResources().getColor(android.R.color.transparent));              transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));              if(cont >= 50){                  radius2 = (radius2 >= getWidth()/2)? (float)getWidth()/2 : radius2+1;              }else{                  radius2 = (radius2 >= getWidth()/2-Utils.dpToPx(4, getResources()))? (float)getWidth()/2-Utils.dpToPx(4, getResources()) : radius2+1;              }              temp.drawCircle(getWidth()/2, getHeight()/2, radius2, transparentPaint);              canvas.drawBitmap(bitmap, 0, 0, new Paint());              if(radius2 >= getWidth()/2-Utils.dpToPx(4, getResources()))                  cont++;              if(radius2 >= getWidth()/2)                  firstAnimationOver = true;          }      }

83-121,第一次绘制会调用的方法。

如果圆的radius有大小则根据尺寸来绘画没有就根据空间大小来设定大小(一开始肯定是0,然后慢慢自增,也就是我们那个灰色圈渐渐变大的效果)
当增长到一定程度了,就开始绘画空心圆部分的操作,空心圆也是渐渐掏空,直至完全达到控件实体的大小动画才停止。整个变化过彻骨结束之后把判断是否为第一次的firstAnimationOver状态改变

整个过程invalidate();使得逻辑不断执行。

    int arcD = 1;      int arcO = 0;      float rotateAngle = 0;      int limite = 0;      /** * Draw second animation of view * @param canvas */      private void drawSecondAnimation(Canvas canvas){          if(arcO == limite)              arcD+=6;          if(arcD >= 290 || arcO > limite){              arcO+=6;              arcD-=6;          }          if(arcO > limite + 290){              limite = arcO;              arcO = limite;              arcD = 1;          }          rotateAngle += 4;          canvas.rotate(rotateAngle,getWidth()/2, getHeight()/2);            Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);          Canvas temp = new Canvas(bitmap);          Paint paint = new Paint();          paint.setAntiAlias(true);          paint.setColor(backgroundColor);  // temp.drawARGB(0, 0, 0, 255);          temp.drawArc(new RectF(0, 0, getWidth(), getHeight()), arcO, arcD, true, paint);          Paint transparentPaint = new Paint();          transparentPaint.setAntiAlias(true);          transparentPaint.setColor(getResources().getColor(android.R.color.transparent));          transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));          temp.drawCircle(getWidth()/2, getHeight()/2, (getWidth()/2)- Utils.dpToPx(4, getResources()), transparentPaint);            canvas.drawBitmap(bitmap, 0, 0, new Paint());      }

131-160,非第一次绘制时的实现,这边我来解释下重要部分的逻辑。

  if(arcO == limite)              arcD+=6;          if(arcD >= 290 || arcO > limite){ arcO+=6; arcD-=6; }          if(arcO > limite + 290){ limite = arcO; arcO = limite; arcD = 1; }

大圆弧最大值为290,满了就收缩,到底到头了都增长,用2个变量做差值反向计算,290为边界值

 canvas.rotate(rotateAngle,getWidth()/2, getHeight()/2);

旋转操作,每一次角度自增4

分析:

就是第一次进去画一个从圆心缩放的效果,然后之后都是走290圆弧增大缩小的无限循环计算绘画,计算这部分逻辑还是有点搞脑子的,大家可以仔细思考思考。

源码:https://github.com/ddwhan0123/BlogSample/blob/master/MaterialDesignProgress.zip