1、仿58同城数据加载缓冲控件动画效果
先看下效果图:
58city.gif
#######1.1 实现步骤拆解
(1)自定义一个ShapeView继承自View,按顺序分别重绘三角形、圆形和正方形,如此不断重复。
(2)自定义一个ViewGroup,创建一个ShapeView加进布局当中,并往布局中再添加一个TextView以显示文字。onLayout分别摆放好ShapeView和TextView。
(3)使用属性动画实现ShapeView的上下移动和旋转
#######1.2 实现分析
2.1 自定义一个ShapeView
自定义一个ShapeView实现三种形状切换效果的原理也很简单。圆形通过画布的canvas.drawCircle()方法来绘制,正方形通过画布的canvas.drawRect()方法来绘制。等边三角形的绘制稍复杂,可通过绘制路径来实现: canvas.drawPath(),等边三角形路径的三个顶点坐标通过计算得出,以下是分析图 :
triangle.png
如上图,控件ShapeView的宽高可通过getMeasureHeight()或getMeasureWidth()获得,这里测量时已确保ShapeView的宽高相等。因此,三角形边长S即为控件宽或高。
然后,如上图,三角形的三个顶点A 、B 、C即可通过勾股定理算出。
三角形路径设置代码如下:
Path trianglePath = new Path();
trianglePath.moveTo(getWidth() / 2f, 0);
trianglePath.lineTo(0, (float) (Math.sqrt(3) * getHeight() / 2)); // 等边三角形
trianglePath.lineTo(getWidth(), (float) (Math.sqrt(3) * getHeight() / 2));
trianglePath.close();
确定好三个形状的绘制方法后,就可以循环地延时一秒钟,不断地改变当前所要绘制的图形形状,调用 invalidate()方法实现图形的重绘。三种图形绘制方法如下 :
@Override
protected void onDraw(Canvas canvas) {
switch (mShape) { // 当前所要绘制的形状
case circle: // 圆
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getHeight() / 2f, circlePaint);
break;
case rect: // 正方形
canvas.drawRect(0, 0, getWidth(), getHeight(), rectPaint);
break;
case triangle: // 三角形
canvas.drawPath(trianglePath, trianglePaint);
break;
}
}
2.2 自定义一个布局ShapeChangeLoadingViewGroup。
第二步骤就是自定义一个布局ShapeChangeLoadingViewGroup,继承自ViewGroup。再创建ShapeView和一个TextView,TextView用于显示文字“拼命加载中...”。这个步骤的主要内容在于布局,将TextView放在ViewGroup的最底部,ShapeView放在上面。ShapeChangeLoadingViewGroup的布局部分代码如下 :
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int shapeLeft = getWidth() / 2 - mShapeView.getMeasuredWidth() / 2;
int shapeTop = (int) (mShapeView.getMeasuredHeight() * 3.5);
int shapeRight = shapeLeft + mShapeView.getMeasuredWidth();
int shapeBottom = shapeTop + mShapeView.getMeasuredHeight();
mShapeView.layout(shapeLeft, shapeTop, shapeRight, shapeBottom);
int textLeft = 0;
int textTop = getHeight() - mLoadTextView.getMeasuredHeight();
int textRight = getWidth();
int textBottom = getHeight();
mLoadTextView.layout(textLeft, textTop, textRight, textBottom);
setAnimator();
}
2.3 使用属性动画让ShapeView动起来
第三部就是实现ShapeView上下移动以及旋转的效果,这里分别使用了属性动画的translationY 和 rotation 两个属性实现。代码如下 :
translationObjectAnimator = ObjectAnimator.ofFloat(mShapeView,
"translationY", -distance, 0, -distance); //实现上下平移
translationObjectAnimator.setDuration(1500);
translationObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
translationObjectAnimator.setRepeatCount(-1); // -1 无限循环
rotationObjectAnimator = ObjectAnimator.ofFloat(mShapeView,
"rotation", 0f, 360f); // 实现360度旋转
rotationObjectAnimator.setDuration(1500);
rotationObjectAnimator.setRepeatCount(-1); // -1 无限循环
rotationObjectAnimator.start();
translationObjectAnimator.start();
最后效果实现了,但有一点要优化。对外提供一个接口,将属性动画资源释放 :
public void release(){ //优化,释放属性动画资源
if (translationObjectAnimator != null){
translationObjectAnimator.end();
translationObjectAnimator.removeAllListeners();
translationObjectAnimator.cancel();
translationObjectAnimator = null;
}
if (rotationObjectAnimator != null){
rotationObjectAnimator.end();
rotationObjectAnimator.removeAllListeners();
rotationObjectAnimator.cancel();
rotationObjectAnimator = null;
}
if (mShapeView != null) mShapeView.setRepeat(false);
}
2、另一个加载控件
效果看图 :
loadingView.gif
实现步骤 :
(1) 自定义一个CircleView继承自View,画一个圆,对外提供可改变颜色的接口。
(2) 自定义一个LoadingView继承自ViewGroup,创建三个CircleView,分别摆放在LoadingView的左、中、右的位置。
(3) 利用属性动画实现左右两个CircleView往中间方向来回移动,中间的CircleView保持不动。
(4) 监听属性动画的回调,实现每移动一次,三个CircleView颜色互换一次,达到变色的效果。
这部分实现比较简单,实现原理和上面第一个控件相似,这里不再详细讲述。看源码:https://github.com/EthanLee-88/LoadingView