前言
这是仿照58同城的加载动画。主要用到的知识点包括自定义view和和属性动画。 这个是不难的。
showtime
第一,先考虑自定义view 继承谁 (Linealayout)
package jftclient.shuhui.com.a58;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import javax.xml.transform.dom.DOMLocator;
/**
* Created by 梁想想 on 2018/3/27.
*/
public class Loadding extends LinearLayout {
private Context mContext ;
public static final int Animation_Duration = 500 ;
private FloatView floatView;
private ImageView shadeView;
private Shape mCurrentShape = Shape.SHAPE_CIRCLE ;
enum Shape{
SHAPE_CIRCLE, SHAPE_TRIANGLE, SHAPE_RECTANGLE
}
public Loadding(Context context) {
this(context,null);
}
public Loadding(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public Loadding(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
View view = View.inflate(context, R.layout.item_loadding, this);
floatView = (FloatView) view.findViewById(R.id.floatView);
shadeView = (ImageView) view.findViewById(R.id.shadeView);
mContext = context ;
startDownAnimation();
}
private void startDownAnimation() {
//开始下落
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(floatView,
"translationY",
ScreenUtils.dip2px(mContext, 40));
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(shadeView,
"scaleX", 1.0f, 0.3f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1, objectAnimator);
//设置速度插值器
animatorSet.setInterpolator(new AccelerateInterpolator());
animatorSet.setDuration(Animation_Duration);
animatorSet.start();
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//当 animatorset 动画完成的时候调用
//开始上去
switch (mCurrentShape)
{
case SHAPE_RECTANGLE:
mCurrentShape = Shape.SHAPE_CIRCLE;
break;
case SHAPE_CIRCLE:
mCurrentShape = Shape.SHAPE_TRIANGLE;
break;
case SHAPE_TRIANGLE:
mCurrentShape = Shape.SHAPE_RECTANGLE ;
break;
}
floatView.setCurrentShape(mCurrentShape);
startUpAnimation();
}
});
}
private void startUpAnimation() {
//开始上升
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(floatView,
"translationY",
ScreenUtils.dip2px(mContext, -40));
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(shadeView,
"scaleX", 0.3f,1.0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1, objectAnimator);
//设置速度插值器
animatorSet.setInterpolator(new DecelerateInterpolator());
animatorSet.setDuration(Animation_Duration);
animatorSet.start();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
startDownAnimation();
switch (mCurrentShape)
{
case SHAPE_RECTANGLE:
ObjectAnimator animator = ObjectAnimator.ofFloat(floatView,"rotation",-360,0);
animator.setDuration(Animation_Duration);
animator.start();
break;
case SHAPE_CIRCLE:
case SHAPE_TRIANGLE:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(floatView,"rotation",0,360);
animator1.setDuration(Animation_Duration);
animator1.start();
break;
}
}
});
}
/**
* 解决内存优化问题
*/
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if(visibility == GONE){
// 隐藏 清除动画
floatView.clearAnimation();
shadeView.clearAnimation();
// 删除这个View 用代码 删除
ViewGroup parent = (ViewGroup) this.getParent();
if(parent != null){
parent.removeView(this);
}
}
}
}
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<jftclient.shuhui.com.a58.FloatView
android:id="@+id/floatView"
android:layout_width="30dp"
android:layout_height="30dp" />
<ImageView
android:layout_marginTop="40dp"
android:id="@+id/shadeView"
android:layout_width="25sp"
android:layout_height="5sp"
android:background="@drawable/foot_shade"
/>
<TextView
android:layout_marginTop="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="玩命加载中..."/>
</LinearLayout>
分析: 为什么要继承Linnearlayout ?
首先动画中有三个控件 最上面的是一个imageview 中间的也是一个imageview,最下面是一个textview ,上下结构最好继承linearLayout ,也可以继承RelativeLayout ,但是效果都是一样的
第二步:自定义上方不断改变的图片
package jftclient.shuhui.com.a58;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by 梁想想 on 2018/3/27.
*/
public class FloatView extends View {
private Context mContext ;
private Paint mPaint ;
private int height;
private int width;
private Loadding.Shape mCurrentShape = Loadding.Shape.SHAPE_CIRCLE ;
public FloatView(Context context) {
this(context,null);
}
public FloatView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public FloatView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context ;
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setDither(true);
mPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = getMeasuredHeight();
width = getMeasuredWidth();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (mCurrentShape)
{
case SHAPE_RECTANGLE: //矩形 画圆
mPaint.setColor(Color.RED);
canvas.drawCircle(width / 2 ,height / 2 ,width / 2 ,mPaint);
break;
case SHAPE_CIRCLE: //圆型
mPaint.setColor(Color.BLUE);
Path path = new Path();
path.moveTo(width /2 ,0 );
path.lineTo(0, (float) Math.sqrt(3) / 2 * width );
path.lineTo(width, (float) Math.sqrt(3) / 2 * width );
path.close();
canvas.drawPath(path,mPaint);
break;
case SHAPE_TRIANGLE: //三角形
mPaint.setColor(Color.GREEN);
canvas.drawRect(0,0,width,height,mPaint);
break;
default:
break;
}
}
public void setCurrentShape(Loadding.Shape mCurrentShape){
this.mCurrentShape = mCurrentShape ;
invalidate();
}
}
解析: 这个就是根据不同的形状状态去不断使用canvas画不同的形状 。没有什么技术可言
**第三步:在 布局中使用**
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context="jftclient.shuhui.com.a58.MainActivity"
<jftclient.shuhui.com.a58.Loadding
android:id="@+id/loaddingView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</jftclient.shuhui.com.a58.Loadding>
</RelativeLayout>
其实 自定义view 挺简单的,只需要搞懂逻辑就可以了。