Android动画特效之水波(地震波)报警动画

需求:
工作中有个项目需求:在GridView列表中展示水波(地震波)报警动画效果,显示所有区域的故障数量,以及故障的严重程度(故障数量越大表示越严重,水波扩散越快,状态越醒目),现将这一实现方式整理成文,给有需要的小伙伴一点帮助,同时希望,开源互助的精神能激励更多未来的大牛门前行在coding的道路上!

效果
实现的效果如下
Android 水波 地震波 动画效果
效果比较简单,可根据需求自定义其他颜色的状态(比如黄色表示警告、绿色表示正常等)同时显示在GridView中的item中,是否出现波纹可进行控制,以作为对比效果,如下图所示:
Android 水波 地震波 动画效果对比

附上源码地址:http://download.csdn.net/detail/daijin888888/8771873
(直接导入Eclipse ADT即可,出现乱码请调整项目编码,笔者的是UTF-8编码)

实现方式
首先说明涉及的主要知识点:

  • GridView+Adapter
  • 自定义View
  • Handle

项目结构图如下:
项目结构图
MainActivity:主Activity,生成数据源
StateAdapter:适配器,适配GridView数据
StatePojo:数据实体
MyAlarmView:自定义视图,重要部分

我们先自定义视图,也是实现报警效果的主要组件,通常情况下,要在Android中绘图,需要先创建一个继承自View类的视图,并且在该类中重写它的onDraw方法,然后在显示绘图的Activity中添加该视图。这里主要用到了Paint类和Canvas类:

  • Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度和填充效果等信息。使用Paint类时,需要先创建该类的对象,可以通过该类的构造函数实现,然后再通过该对象提供的方法对画笔的默认设置进行改变。
  • Canvas类代表画布,通过该类提供的构造方法,可以绘制各种图形。(具体使用方法本篇不再赘述)

MyAlarmView.java

package com.test.widget;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * @author daij 地震波效果,可根据故障严重程度调节闪烁速度
 */
public class MyAlarmView extends View {

	private Paint paint;
	private int maxWidth = 128;
	private boolean isStarting = false;
	private int delay;
	private List<String> alphaList = new ArrayList<String>();
	private List<String> startWidthList = new ArrayList<String>();

	public MyAlarmView(Context context) {
		super(context);
		init();
	}

	public MyAlarmView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public MyAlarmView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	private void init() {
		paint = new Paint();
		paint.setColor(Color.RED);// 此处颜色可以改为自己喜欢的
		alphaList.add("128");// 圆心的不透明度
		startWidthList.add("0");
	}

	@Override
	public void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		setBackgroundColor(Color.TRANSPARENT);// 颜色:完全透明
		// 依次绘制 同心圆
		for (int i = 0; i < alphaList.size(); i++) {
			int alpha = Integer.parseInt(alphaList.get(i));
			int startWidth = Integer.parseInt(startWidthList.get(i));
			paint.setAlpha(alpha);// 设置透明度
			canvas.drawCircle(getWidth() / 2, getHeight() / 2, startWidth,
					paint);
			// 同心圆扩散
			if (isStarting && alpha > 0 && startWidth < maxWidth) {
				alphaList.set(i, (alpha - 1) + "");
				startWidthList.set(i, (startWidth + 1) + "");
			}
		}
		if (isStarting
				&& Integer
						.parseInt(startWidthList.get(startWidthList.size() - 1)) == maxWidth / 5) {
			alphaList.add("128");
			startWidthList.add("0");
		}
		// 同心圆数量达到6个,删除最外层圆
		if (isStarting && startWidthList.size() == 6) {
			startWidthList.remove(0);
			alphaList.remove(0);
		}
		postDelayed(new Runnable() {
			@Override
			public void run() {
				// 刷新界面
				invalidate();
			}
		}, delay);
	}

	// 地震波开始/继续进行
	public void start() {
		isStarting = true;
	}

	// 地震波暂停
	public void stop() {
		isStarting = false;
	}

	public boolean isStarting() {
		return isStarting;
	}

	/**
	 * 根据传入的数值决定刷新的频度,数值越大,刷新越快,效果越醒目
	 * 
	 * @param red
	 */
	public void handleDelay(int red) {
		delay = 100 - red;
	}

}

以上代码中实现不同闪烁强度的部分是handleDelay(int red);【用于设置延时时长】和postDelayed(new Runnable());【用于异步请求,延时刷新界面】,值得注意的是,这里的数据量不大,处理逻辑也较简单,所以可以使用这种多线程异步消息通信机制。


再来设计实体类
StatePojo.java

public class StatePojo {

	public static final String TAG = "StatePojo";

	public String area;
	public int red;// 这里我只设置了红色报警,以下其他属性可根据需求选择
	public int blue;
	public int yellow;

	public String getArea() {
		return area;
	}

	public StatePojo setArea(String area) {
		this.area = area;
		return this;
	}

	public int getRed() {
		return red;
	}

	public StatePojo setRed(int red) {
		this.red = red;
		return this;
	}

	public int getBlue() {
		return blue;
	}

	public StatePojo setBlue(int blue) {
		this.blue = blue;
		return this;
	}

	public int getYellow() {
		return yellow;
	}

	public StatePojo setYellow(int yellow) {
		this.yellow = yellow;
		return this;
	}
}

数据实体类实现后,设计Adapter类,里面用到了static class ViewHolder{}视图优化技术,如下:
StateAdapter .java

package com.test.app.adapter;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.alarmtest.R;
import com.test.app.entity.StatePojo;
import com.test.widget.MyAlarmView;

/**
 * @author daij
 * @version 1.0
 * 
 *          状态的adapter
 */
public class StateAdapter extends BaseAdapter {
	Context context;
	private List<StatePojo> messages = null;
	private int resourceId;

	public StateAdapter(Context con) {
		this.context = con;
	}

	public StateAdapter(Context con, int gridviewItem,
			ArrayList<StatePojo> messages) {
		this.context = con;
		resourceId = gridviewItem;
		this.messages = messages;
	}

	@Override
	public int getCount() {
		// return messages.size();
		return 8;
	}

	@Override
	public StatePojo getItem(int arg0) {
		return messages.get(arg0);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View rowView = convertView;
		ViewHolder viewHolder;
		final StatePojo state = getItem(position);

		if (rowView == null) {
			LayoutInflater vi = (LayoutInflater) context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			rowView = vi.inflate(resourceId, parent, false);
			viewHolder = new ViewHolder();

			// 配置ViewHolder
			viewHolder.tvArea = (TextView) rowView.findViewById(R.id.tv_area);
			viewHolder.smwWave = (MyAlarmView) rowView
					.findViewById(R.id.swvWave);
			viewHolder.tvRedNum = (TextView) rowView
					.findViewById(R.id.tv_red_state);
			// viewHolder.tvYellowNum = (TextView) rowView
			// .findViewById(R.id.tv_yellow_state);
			// viewHolder.tvBlueNum = (TextView) rowView
			// .findViewById(R.id.tv_blue_state);

			rowView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) rowView.getTag();
		}

		viewHolder.tvArea.setText(state.area);
		viewHolder.smwWave.handleDelay(state.red);
		viewHolder.smwWave.start();
		viewHolder.tvRedNum.setText(String.valueOf(state.red));

		viewHolder.tvRedNum.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				// TODO 处理点击事件
				// context.startActivity(new Intent(context,
				// MalfunctionList.class));
			}
		});
//		 viewHolder.tvYellowNum.setText(String.valueOf(state.yellow));
//		 viewHolder.tvBlueNum.setText(String.valueOf(state.blue));

		return rowView;
	}

	static class ViewHolder {
		// 获取所有item组件
		TextView tvArea;// 地区
		MyAlarmView smwWave;// 水波
		TextView tvRedNum;// 红色
//		 TextView tvYellowNum;// 黄色
//		 TextView tvBlueNum;// 绿色
	}
}


最后,实现主Activity,模拟数据,添加适配:
MainActivity.java

package com.test.app;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;

import com.example.alarmtest.R;
import com.test.app.adapter.StateAdapter;
import com.test.app.entity.StatePojo;

/**
 * @author daij 设备监测
 */
public class MainActivity extends Activity {
	private ArrayList<StatePojo> messages = new ArrayList<StatePojo>();
	private StateAdapter stateAdapter;
	private GridView gvStates;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_monitror);

		setViews();
	}

	private void setViews() {
		gvStates = (GridView) findViewById(R.id.gv_monitor);

		messages.add(new StatePojo().setArea("地区A").setRed(89).setYellow(45)
				.setBlue(1));
		messages.add(new StatePojo().setArea("地区B").setRed(56).setYellow(12)
				.setBlue(3));
		messages.add(new StatePojo().setArea("地区C").setRed(32).setYellow(98)
				.setBlue(4));
		messages.add(new StatePojo().setArea("地区D").setRed(121).setYellow(11)
				.setBlue(5));
		messages.add(new StatePojo().setArea("地区E").setRed(12).setYellow(23)
				.setBlue(9));
		messages.add(new StatePojo().setArea("地区F").setRed(0).setYellow(12)
				.setBlue(7));
		messages.add(new StatePojo().setArea("地区G").setRed(45).setYellow(25)
				.setBlue(8));
		messages.add(new StatePojo().setArea("地区H").setRed(65).setYellow(8)
				.setBlue(0));

		// 设置的适配器
		stateAdapter = new StateAdapter(this, R.layout.gridview_item, messages);
		gvStates.setAdapter(stateAdapter);
	}
}


再附上布局文件:
activity_monitror.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/monitor_bg"
    tools:context=".Monitor" >

    <GridView
        android:id="@+id/gv_monitor"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:columnWidth="90dp"
        android:gravity="center"
        android:horizontalSpacing="8dp"
        android:numColumns="2"
        android:stretchMode="columnWidth"
        android:verticalSpacing="8dp" >
    </GridView>

</RelativeLayout>

gridview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/gridview_item_bg"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="5dp" >

    <TextView
        android:id="@+id/tv_area"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="10dp"
        android:textColor="@color/gridview_item_text_color"
        android:textSize="25sp" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0.5dp"
        android:layout_gravity="bottom"
        android:background="@color/white" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal" >

        <FrameLayout
            android:id="@+id/state"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal" >

            <com.test.widget.MyAlarmView
                android:id="@+id/swvWave"
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:gravity="center" />

            <TextView
                android:id="@+id/tv_red_state"
                android:layout_width="45dp"
                android:layout_height="45dp"
                android:layout_gravity="center"
                android:background="@drawable/state_item_red"
                android:gravity="center"
                android:padding="2dp"
                android:textColor="@color/white"
                android:textSize="20sp" />
        </FrameLayout>
        <!-- 取消下面和Adapter中的注释即可显示红黄绿对比效果 -->
        <!--
        <TextView
            android:id="@+id/tv_yellow_state"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_margin="5dp"
            android:background="@drawable/state_item_yellow"
            android:gravity="center"
            android:padding="4dp"
            android:textColor="@color/white"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/tv_blue_state"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:background="@drawable/state_item_blue"
            android:gravity="center"
            android:padding="4dp"
            android:textColor="@color/white"
            android:textSize="16sp" />
        -->
    </LinearLayout>

</LinearLayout>

为了实现较好看的样式,自定义TextView背景边框:
state_item_red.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    android:useLevel="false" >

    <solid android:color="@color/red_state" />
    <!-- state_item_blue.xml和state_item_yellow.xml中只需将这里对应分别改为@color/blue_state和@color/yellow_state即可 -->

    <padding
        android:bottom="1dp"
        android:left="2dp"
        android:right="2dp"
        android:top="1dp" />

    <solid android:color="@color/red_state" />
    <!-- state_item_blue.xml和state_item_yellow.xml中只需将这里对应分别改为@color/blue_state和@color/yellow_state即可 -->

    <stroke
        android:width="1dp"
        android:color="@android:color/white" />

    <size
        android:height="15dp"
        android:width="15dp" />

</shape>

最后附上资源文件:
colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="gridview_item_bg">#E4E7E7</color>
    <!-- 状态表格item的背景 -->
    <color name="gridview_item_text_color">#5F8FA3</color>
    <!-- 状态表格item的文字颜色 -->
    <color name="white">#FFFFFFFF</color>
    <color name="red_state">#F23829</color>
    <!-- 红色状态 -->
    <color name="yellow_state">#F2D883</color>
 	<!-- 黄色状态 -->
    <color name="blue_state">#5D9A25</color>
 	<!-- 绿色状态 -->
    <color name="monitor_bg">#D6DEE1</color>
    <!-- 设备监测页背景 -->

</resources>

至此,所有代码构建完成,附上源码。
http://download.csdn.net/detail/daijin888888/8771873
GitHub(给个星杯~):
https://github.com/VingeDai/AlarmAnimationDemo
请尊重原创,转载请附上原文地址,谢谢!
原文地址:http://blog.csdn.net/daijin888888/article/details/46357515

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值