android用canvas绘制两种波纹效果
首先看一下Solo 火爆足球动态壁纸,

/****/package com.kince.rippleview;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.View;/*** @author kince* @category 波纹* @since 2014.8.9* @version v1.0.0**/public class RippleView extends View { private int mScreenWidth; private int mScreenHeight; private Bitmap mRippleBitmap; private Paint mRipplePaint = new Paint(); private int mBitmapWidth; private int mBitmapHeight; private boolean isStartRipple; private int heightPaddingTop; private int heightPaddingBottom; private int widthPaddingLeft; private int widthPaddingRight; private RectF mRect = new RectF(); private int rippleFirstRadius = 0; private int rippleSecendRadius = -33; private int rippleThirdRadius = -66; private Paint textPaint = new Paint(); private String mText="点击我吧"; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); invalidate(); if (isStartRipple) { rippleFirstRadius++; if (rippleFirstRadius > 100) { rippleFirstRadius = 0; } rippleSecendRadius++; if (rippleSecendRadius > 100) { rippleSecendRadius = 0; } rippleThirdRadius++; if (rippleThirdRadius > 100) { rippleThirdRadius = 0; } sendEmptyMessageDelayed(0, 20); } } }; /** * @param context */ public RippleView(Context context) { super(context); // TODO Auto-generated constructor stub init(); } /** * @param context * @param attrs */ public RippleView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(); } /** * @param context * @param attrs * @param defStyleAttr */ public RippleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub init(); } private void init() { mRipplePaint.setColor(4961729); mRipplePaint.setAntiAlias(true); mRipplePaint.setStyle(Paint.Style.FILL); textPaint.setTextSize(26); textPaint.setAntiAlias(true); textPaint.setStyle(Paint.Style.FILL); textPaint.setColor(Color.WHITE); mRippleBitmap = BitmapFactory.decodeStream(getResources() .openRawResource(R.drawable.easy3d_ic_apply)); mBitmapWidth = mRippleBitmap.getWidth(); mBitmapHeight = mRippleBitmap.getHeight(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); int mh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); int mw = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); if (mBitmapWidth < 2 * mBitmapHeight) { mBitmapWidth = (2 * mBitmapHeight); } setMeasuredDimension(mBitmapWidth, mBitmapHeight); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); if (isStartRipple) { float f1 = 3 * mBitmapHeight / 10; mRipplePaint.setAlpha(255); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7 * mBitmapHeight / 10, mRipplePaint); int i1 = (int) (220.0F - (220.0F - 0.0F) / 100.0F * rippleFirstRadius); mRipplePaint.setAlpha(i1); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7 * mBitmapHeight / 10 + f1 * rippleFirstRadius / 100.0F, mRipplePaint); if (rippleSecendRadius >= 0) { int i3 = (int) (220.0F - (220.0F - 0.0F) / 100.0F * rippleSecendRadius); mRipplePaint.setAlpha(i3); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7 * mBitmapHeight / 10 + f1 * rippleSecendRadius / 100.0F, mRipplePaint); } if (rippleThirdRadius >= 0) { int i2 = (int) (220.0F - (220.0F - 0.0F) / 100.0F * rippleThirdRadius); mRipplePaint.setAlpha(i2); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7 * mBitmapHeight / 10 + f1 * rippleThirdRadius / 100.0F, mRipplePaint); } } mRipplePaint.setAlpha(30); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, mBitmapHeight, mRipplePaint); mRipplePaint.setAlpha(120); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 9 * mBitmapHeight / 10, mRipplePaint); mRipplePaint.setAlpha(180); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 8 * mBitmapHeight / 10, mRipplePaint); mRipplePaint.setAlpha(255); canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7 * mBitmapHeight / 10, mRipplePaint); float length = textPaint.measureText(mText); canvas.drawText(mText, (mBitmapWidth - length) / 2, mBitmapHeight * 3 / 4, textPaint); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); mScreenWidth = w; mScreenHeight = h; confirmSize(); invalidate(); } private void confirmSize() { int minScreenSize = Math.min(mScreenWidth, mScreenHeight); int widthOverSize = mScreenWidth - minScreenSize; int heightOverSize = mScreenHeight - minScreenSize; heightPaddingTop = (getPaddingTop() + heightOverSize / 2); heightPaddingBottom = (getPaddingBottom() + heightOverSize / 2); widthPaddingLeft = (getPaddingLeft() + widthOverSize / 2); widthPaddingRight = (getPaddingRight() + widthOverSize / 2); int width = getWidth(); int height = getHeight(); mRect = new RectF(widthPaddingLeft, heightPaddingTop, width - widthPaddingRight, height * 2 - heightPaddingBottom); } public void stratRipple() { isStartRipple = true; handler.sendEmptyMessage(0); }}下图是某个应用的流量显示界面,使用的是上面说的第二种形式。

/****/package com.kince.waveview;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.RectF;import android.os.Handler;import android.os.Parcel;import android.os.Parcelable;import android.util.AttributeSet;import android.view.View;import android.widget.ProgressBar;/*** @author kince* @category View必须是正方形**/public class WaterWaveView extends View { private Context mContext; private int mScreenWidth; private int mScreenHeight; private Paint mRingPaint; private Paint mCirclePaint; private Paint mWavePaint; private Paint linePaint; private Paint flowPaint; private Paint leftPaint; private int mRingSTROKEWidth = 15; private int mCircleSTROKEWidth = 2; private int mLineSTROKEWidth = 1; private int mCircleColor = Color.WHITE; private int mRingColor = Color.WHITE; private int mWaveColor = Color.WHITE; private Handler mHandler; private long c = 0L; private boolean mStarted = false; private final float f = 0.033F; private int mAlpha = 50;// 透明度 private float mAmplitude = 10.0F; // 振幅 private float mWateLevel = 0.5F;// 水高(0~1) private Path mPath; private String flowNum = "1024M"; private String flowLeft = "还剩余"; /** * @param context */ public WaterWaveView(Context context) { super(context); // TODO Auto-generated constructor stub mContext = context; init(mContext); } /** * @param context * @param attrs */ public WaterWaveView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub mContext = context; init(mContext); } /** * @param context * @param attrs * @param defStyleAttr */ public WaterWaveView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub mContext = context; init(mContext); } private void init(Context context) { mRingPaint = new Paint(); mRingPaint.setColor(mRingColor); mRingPaint.setAlpha(50); mRingPaint.setStyle(Paint.Style.STROKE); mRingPaint.setAntiAlias(true); mRingPaint.setStrokeWidth(mRingSTROKEWidth); mCirclePaint = new Paint(); mCirclePaint.setColor(mCircleColor); mCirclePaint.setStyle(Paint.Style.STROKE); mCirclePaint.setAntiAlias(true); mCirclePaint.setStrokeWidth(mCircleSTROKEWidth); linePaint = new Paint(); linePaint.setColor(mCircleColor); linePaint.setStyle(Paint.Style.STROKE); linePaint.setAntiAlias(true); linePaint.setStrokeWidth(mLineSTROKEWidth); flowPaint = new Paint(); flowPaint.setColor(mCircleColor); flowPaint.setStyle(Paint.Style.FILL); flowPaint.setAntiAlias(true); flowPaint.setTextSize(36); leftPaint = new Paint(); leftPaint.setColor(mCircleColor); leftPaint.setStyle(Paint.Style.FILL); leftPaint.setAntiAlias(true); leftPaint.setTextSize(18); mWavePaint = new Paint(); mWavePaint.setStrokeWidth(1.0F); mWavePaint.setColor(mWaveColor); mWavePaint.setAlpha(mAlpha); mPath = new Path(); mHandler = new Handler() { @Override public void handleMessage(android.os.Message msg) { if (msg.what == 0) { invalidate(); if (mStarted) { // 不断发消息给自己,使自己不断被重绘 mHandler.sendEmptyMessageDelayed(0, 60L); } } } }; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = measure(widthMeasureSpec, true); int height = measure(heightMeasureSpec, false); if (width < height) { setMeasuredDimension(width, width); } else { setMeasuredDimension(height, height); } } /** * @category 测量 * @param measureSpec * @param isWidth * @return */ private int measure(int measureSpec, boolean isWidth) { int result; int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom(); if (mode == MeasureSpec.EXACTLY) { result = size; } else { result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight(); result += padding; if (mode == MeasureSpec.AT_MOST) { if (isWidth) { result = Math.max(result, size); } else { result = Math.min(result, size); } } } return result; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); mScreenWidth = w; mScreenHeight = h; } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); // 得到控件的宽高 int width = getWidth(); int height = getHeight(); setBackgroundColor(mContext.getResources().getColor( R.color.holo_purple2)); canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2, mScreenWidth / 4, mRingPaint); canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2, mScreenWidth / 4 - mRingSTROKEWidth / 2, mCirclePaint); canvas.drawLine(mScreenWidth * 3 / 8, mScreenHeight * 5 / 8, mScreenWidth * 5 / 8, mScreenHeight * 5 / 8, linePaint); float num = flowPaint.measureText(flowNum); canvas.drawText(flowNum, mScreenWidth * 4 / 8 - num / 2, mScreenHeight * 4 / 8, flowPaint); float left = leftPaint.measureText(flowLeft); canvas.drawText(flowLeft, mScreenWidth * 4 / 8 - left / 2, mScreenHeight * 3 / 8, leftPaint); // 如果未开始(未调用startWave方法),绘制一个扇形 if ((!mStarted) || (mScreenWidth == 0) || (mScreenHeight == 0)) { RectF oval = new RectF(mScreenWidth / 4 + mRingSTROKEWidth / 2, mScreenHeight / 4 + mRingSTROKEWidth / 2, mScreenWidth * 3 / 4 - mRingSTROKEWidth / 2, mScreenHeight * 3 / 4 - mRingSTROKEWidth / 2);// 设置个新的长方形,扫描测量 canvas.drawArc(oval, 0, 180, true, mWavePaint); return; } // 绘制,即水面静止时的高度 RectF oval = new RectF(mScreenWidth / 4 + mRingSTROKEWidth / 2, mScreenHeight / 4 + mRingSTROKEWidth / 2 + mAmplitude * 2, mScreenWidth * 3 / 4 - mRingSTROKEWidth / 2, mScreenHeight * 3 / 4 - mRingSTROKEWidth / 2);// 设置个新的长方形,扫描测量 canvas.drawArc(oval, 0, 180, true, mWavePaint); if (this.c >= 8388607L) { this.c = 0L; } // 每次onDraw时c都会自增 c = (1L + c); float f1 = mScreenHeight * (1.0F - mWateLevel); int top = (int) (f1 + mAmplitude); mPath.reset(); int startX = mScreenWidth / 2 - mScreenWidth / 4 + mRingSTROKEWidth / 2; // 波浪效果 while (startX < mScreenWidth / 2 + mScreenWidth / 4 - mRingSTROKEWidth / 2) { int startY = (int) (f1 - mAmplitude * Math.sin(Math.PI * (2.0F * (startX + this.c * width * this.f)) / width)); canvas.drawLine(startX, startY, startX, top, mWavePaint); startX++; } canvas.restore(); } @Override public Parcelable onSaveInstanceState() { // Force our ancestor class to save its state Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.progress = (int) c; return ss; } @Override public void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); c = ss.progress; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); // 关闭硬件加速,防止异常unsupported operation exception this.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); } /** * @category 开始波动 */ public void startWave() { if (!mStarted) { this.c = 0L; mStarted = true; this.mHandler.sendEmptyMessage(0); } } /** * @category 停止波动 */ public void stopWave() { if (mStarted) { this.c = 0L; mStarted = false; this.mHandler.removeMessages(0); } } /** * @category 保存状态 */ static class SavedState extends BaseSavedState { int progress; /** * Constructor called from {@link ProgressBar#onSaveInstanceState()} */ SavedState(Parcelable superState) { super(superState); } /** * Constructor called from {@link #CREATOR} */ private SavedState(Parcel in) { super(in); progress = in.readInt(); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(progress); } public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; }}github下载地址:
android用canvas绘制两种波纹效果的更多相关文章
- Android 抗锯齿的两种方法
Android 抗锯齿的两种方法 (其一:paint.setAntiAlias(ture);paint.setBitmapFilter(true)) 在Android中,目前,我知道有两种出现锯齿 ...
- android emulator启动的两种方法详解
android emulator启动的两种方法详解 转https://blog.csdn.net/TTS_Kevin/article/details/7452237 对于android学习者,模 ...
- Android 的保活的两种解决方案
原文链接:http://blog.csdn.net/pan861190079/article/details/72773549 详细的阐述了 Android 的保活的两种解决方案 —— 由panhao ...
- Android自定义控件 -Canvas绘制折线图(实现动态报表效果)
有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas ...
- Android中BroadcastReceiver的两种注册方式(静态和动态)详解
今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...
- Android中Fragment的两种创建方式
fragment是Activity中用户界面的一个行为或者是一部分.你可以在一个单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再使用.你可以认 ...
- Android 高级UI设计笔记23:Android 夜间模式之 两种常用方法(降低屏幕亮度+替换theme)
1. 夜间模式 所谓的夜间模式,就是能够根据不同的设定,呈现不同风格的界面给用户,而且晚上看着不伤眼睛.特别是一些新闻类App实现夜间模式是非常人性化的,增强用户体验. 2. 我根据网上的资料 以及自 ...
- android xml实现animation 4种动画效果
animation有四种动画类型 分别为alpha(透明的渐变).rotate(旋转).scale(尺寸伸缩).translate(移动),二实现的分发有两种,一种是javaCode,另外一种是XML ...
- Android请求服务器的两种方式--post, get的区别
android中用get和post方式向服务器提交请求_疯狂之桥_新浪博客http://blog.sina.com.cn/s/blog_a46817ff01017yxt.html Android提交数 ...
随机推荐
- memset函数的使用
void *memset(void *s, int ch, size_t n); 说明:将s中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s 关于mem ...
- 一个库搞定各种分享--ShareSDK
ShareSDK是为iOS.Android.WindowsPhone提供社会功能的一个组件,开发者只需10分钟即可集成到自己的APP中,它不仅支持分享给QQ好友.微信好友.微信朋友圈.新浪微博.腾迅微 ...
- CSS 实现图片灰度效果 兼容各种浏览器
CSS 实现图片灰度效果 兼容各种浏览器如360浏览器 CSS实现图片灰度效果就是通过CSS样式让彩色图片呈现为灰色,相当于把一张图像的颜色模式调整为灰度,CSS可以通过以下几种方法来实现灰度效果. ...
- Two-phase Termination
本文参阅[http://ifeve.com/java-two-phase-termination/] Two-phase Termination模式简介 停止线程是一个目标简单而实现却不那么简单的任务 ...
- 数据结构C语言版 有向图的十字链表存储表示和实现
/*1wangxiaobo@163.com 数据结构C语言版 有向图的十字链表存储表示和实现 P165 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h> ...
- android——ListView功能的实现
1.main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:a ...
- Python标准库:内置函数repr(object)
本函数是返回对象object的具体说明字符串. 样例: #repr() print(repr(range(5))) print(repr(help)) print(repr(0x200)) print ...
- Windows多线程
//简单的引出多线程是肿么回事儿....当点击下载的时候,下载内容还没结束也可以点击资源库,其实这就用了另一个线程,弹出“下载完成”对话框的时候,没有点击确定是不能点击主页面内容的,这就是用----- ...
- C# 课堂总结4-类(常用的类)
一.string类 1. str.Length:字符串的长度 *****str[索引号] 2. str.Trim():去除左右两边的空格 *****str.TrimStart():去掉左边的空格str ...
- android handler looper thread
在线程中调用包含创建handler方法的时候,会报错,提示: “need call Looper.prepare()” -- 在创建之前,调用Looper.prepare()方法来创建一个looper ...