Android仿58同城Loading View

oint1572 9年前

来自: http://blog.csdn.net//lcq5211314123/article/details/49101935


今天打开58同城App看到他们的网络加载Loading做的很有新意,是一个三角形,圆形,正方形不同的运动并且切换,这个效果不说有多难,至少很有创意,就着手模仿了一下,先看下效果图:
这里写图片描述
58的更加复杂,在形状运动的过程还一直不停的旋转,旋转的坐标计算太复杂, 还没有搞定,先把这个半成品开源出来。

思路:1.先画一个静态的形状和下面的阴影。         2.通过ValueAnimator不停的改变纵坐标,在动画的监听中拿到 当前的坐标值,重新invalidate()此时的View。       3.在向下的动画执行完毕后,更新Shape。然后让动画不停的运动即可。
package view;  /** * @description 仿58加载View * @author rzq * @date 2015年10月10日 */  public class MyLoadingView extends View  {      /** * 公共变量 */      private Context mContext;      private Resources mResource;      private Paint mPaint;      private Paint mOvalPaint;      /** */      private int mRadius;      private int mDistance;      private int mOvalTop;      private int mOvalHeight;      private int mOvalWidth;        /** * 所有形状的中心位置 */      private int mCenterX, mCenterY;      private int currentCenterY;      private Animator mRotationAnim;      private ValueAnimator mLineAnimDown;      private ValueAnimator mLineAnimUp;      private Shape shape;        public MyLoadingView(Context context)      {          this(context, null);      }        public MyLoadingView(Context context, AttributeSet attrs)      {          super(context);          this.mContext = context;          this.mResource = context.getResources();          init();      }        private void init()      {          mRadius = 10;          mDistance = 50;          mOvalHeight = 3;          mOvalWidth = 10;          mOvalTop = 25;            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);          mPaint.setStyle(Style.FILL);          mPaint.setColor(mResource.getColor(R.color.rect));            mOvalPaint = new Paint(Paint.ANTI_ALIAS_FLAG);          mOvalPaint.setStyle(Style.FILL);          mOvalPaint.setColor(mResource.getColor(R.color.color_666666));            setupAnimations();          shape = Shape.RECT;        }        @Override      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)      {          /** * 宽度最长是矩形的宽,高度最高是矩形的高加上distance */          int width = (mRadius * 2);          int height = (mDistance + mRadius * 2 + mOvalTop + mOvalHeight);          setMeasuredDimension(width, height);          currentCenterY = mCenterX = mCenterY = mRadius;      }        @Override      protected void onDraw(Canvas canvas)      {          switch (shape)          {          case RECT:              drawRect(canvas);              break;          case TRAIL:              drawTrail(canvas);              break;          case CIRCLE:              drawCircle(canvas);              break;          }            drawOval(canvas);      }        /** * 更具中心点的改变,绘制矩形 */      private void drawRect(Canvas canvas)      {          canvas.drawRect(mCenterX - mRadius, currentCenterY - mRadius, mCenterX + mRadius, currentCenterY + mRadius,                  mPaint);      }        private void drawTrail(Canvas canvas)      {          Path path = new Path();          int leftX = 0;          int leftY = currentCenterY + mRadius;          int middleX = mCenterX;          int middleY = currentCenterY - mRadius;          int rightX = mCenterX + mRadius;          int rightY = currentCenterY + mRadius;          path.moveTo(leftX, leftY);          path.lineTo(middleX, middleY);          path.lineTo(rightX, rightY);          path.close();          canvas.drawPath(path, mPaint);      }        private void drawCircle(Canvas canvas)      {          canvas.drawCircle(mCenterX, currentCenterY, mRadius, mPaint);      }        private void drawOval(Canvas canvas)      {          float factory = ((mDistance + mRadius) - currentCenterY) / (float) mDistance;          RectF rectF = new RectF(mCenterX - mOvalWidth * factory, mDistance + mRadius * 2 + mOvalTop, mCenterX                  + mOvalWidth * factory, mDistance + mRadius * 2 + mOvalTop + mOvalHeight);          canvas.drawOval(rectF, mOvalPaint);      }        private void setupAnimations()      {          mRotationAnim = ValueAnimator.ofInt(0, 180);            mLineAnimDown = ValueAnimator.ofInt(mCenterY + mRadius, mDistance);          mLineAnimDown.setInterpolator(new AccelerateInterpolator(1.2f));          mLineAnimDown.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()          {              @Override              public void onAnimationUpdate(ValueAnimator valueAnimator)              {                  currentCenterY = (Integer) valueAnimator.getAnimatedValue();                  invalidate();              }          });            mLineAnimUp = ValueAnimator.ofInt(mDistance, mCenterY + mRadius);          mLineAnimUp.setInterpolator(new DecelerateInterpolator(1.2f));          mLineAnimUp.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()          {              @Override              public void onAnimationUpdate(ValueAnimator valueAnimator)              {                  currentCenterY = (Integer) valueAnimator.getAnimatedValue();                  invalidate();              }          });            mLineAnimDown.addListener(new AnimatorListenerAdapter()          {              @Override              public void onAnimationEnd(Animator animation)              {                  if (shape == Shape.RECT)                  {                      mPaint.setColor(mResource.getColor(R.color.triangle));                      shape = Shape.TRAIL;                  }                  else                  {                      if (shape == Shape.TRAIL)                      {                            mPaint.setColor(mResource.getColor(R.color.circle));                          shape = Shape.CIRCLE;                      }                      else                      {                          mPaint.setColor(mResource.getColor(R.color.rect));                          shape = Shape.RECT;                      }                  }              }          });            final AnimatorSet set = new AnimatorSet();          set.addListener(new AnimatorListener()          {              @Override              public void onAnimationStart(Animator animation)              {              }                @Override              public void onAnimationRepeat(Animator animation)              {              }                @Override              public void onAnimationEnd(Animator animation)              {                  set.start();              }                @Override              public void onAnimationCancel(Animator animation)              {              }          });          set.playSequentially(mLineAnimDown, mLineAnimUp);          set.setDuration(300);          set.setStartDelay(100);          set.start();      }        private enum Shape      {          RECT, TRAIL, CIRCLE;      }  }    用法:直接在布局中引入即可。       <RelativeLayout             xmlns:android="http://schemas.android.com/apk/res /android"       xmlns:app="http://schemas.android.com/apk/res-auto"       xmlns:tools="http://schemas.android.com/tools"       android:layout_width="match_parent"       android:layout_height="match_parent"       android:background="@android:color/white" >        <view.MyLoadingView          android:id="@+id/loadView"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_centerInParent="true" />  </RelativeLayout>

之前看到一个开源View整个动画都是用ViewAnimator衔接起来的,感觉这种方式非常的好,我也尝试的用这种方式实现。

扩张:自定义 View中我为方便将一些属性等的都直接指定了,更好的方式是以自定义属性的方式使用更好。