今天打开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;
}
}
用法:直接在布局中引入即可。
"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" >
"@+id/loadView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
之前看到一个开源View整个动画都是用ViewAnimator衔接起来的,感觉这种方式非常的好,我也尝试的用这种方式实现。
扩张:自定义 View中我为方便将一些属性等的都直接指定了,更好的方式是以自定义属性的方式使用更好。
![欢迎大家关注我的微信公众号,每天会为大家推荐一篇好的技术文章,还有我的视频课程喔](https://img-blog.csdn.net/20160927222837538)