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提交数 ...
随机推荐
- ThinkPHP - 模板引擎
1.导入css/js文件 - CSS文件 <!--<link rel="stylesheet" type="text/css" href=" ...
- BZOJ 3668: [Noi2014]起床困难综合症( 贪心 )
之前以为xor,or,and满足结合律...然后连样例都过不了 早上上体育课的时候突然想出来了...直接处理每一位是1,0的最后结果, 然后从高位到低位贪心就可以了... 滚去吃饭了.. ------ ...
- search_word
一个小程序,用asc码输出自己的名字.要求是,a~z两路输入,输出了一个完整的拼音之后还需要输出一个空格.—— 信息硬件过滤的雏形. module search_word ( clock , rese ...
- Flask web应用
Flask web应用 一.介绍 最近开发要用一个测试环境,是这样的Nginx+uwsgi+flask 的一个结构.下面是一些记录,在Centos 系统上使用Flask 架构部署一个简单的Python ...
- WEB开发:如何用js来模拟服务器的ajax响应,不依赖服务器来编写前端代码
一.问题的提出 目前web前端开发,主流的思路是: 1)编写静态的html文件(不使用模板技术,与服务器无关) 2)页面通过ajax与服务器交互,进行数据的传输,数据格式为json格式 这里存在一个问 ...
- Struts2 学习笔记16 struts标签 part2
接下来说一下if标签.下面是结果图. <li><s:if test="#parameters.age[0]<0">error!</s:if> ...
- 具体解释EBS接口开发之WIP模块接口
整体说明 文档目的 本文档针对WIP模块业务功能和接口进行分析和研究,对採用并发请求方式和调用API方式分别进行介绍 内容 WIP模块经常使用标准表简单介绍 WIP事物处理组成 WIP相关业务流程 W ...
- swift-数组array
// Playground - noun: a place where people can play import UIKit //--------------------------------- ...
- Web 应用程序项目 XXXX 已配置为使用 IIS。 无法访问 IIS 元数据库。您没有足够的特权访问计算机上的 IIS 网站。(转载)
Web 应用程序项目 XXXX 已配置为使用 IIS. 无法访问 IIS 元数据库.您没有足够的特权访问计算机上的 IIS 网站. 2012年05月19日 ⁄ 综合 ⁄ 共 261字 ⁄ 字号 小 中 ...
- sencha touch笔记(6)——路由控制(1)
做项目的时候在界面的跳转上遇到了挺大的问题,本来跳转不想通过路由来控制的,没办法,只能再去看一下路由的跳转方式了. 应用程序的界面发生改变后,可以通过路由让应用程序的界面返回到改变之前的状态,例如浏览 ...