我们先看一下效果

Wave.gif

首先说明这里实现的是刚好一个周期的正弦函数,

我们来说明一下原理,我们是由左向右移动,由于刚好一个周期,所以我们将右边消失的y值正是左边新出现的y值。所以我们可以将函数的y值存储在一个数组里面,然后不断地在数组里面循环地改变不同位置的y值,那么就形成了水波纹效果。

首先我们要两组组数组来存储通过正弦函数的得到的y值,和用来交换时存储的函数。

private float[] mContentOneYs = null;//这两个代表两条线的y值得数据组

private float[] mContentTwoys = null;

private float[] mRestoreOnes = null;//这两个分笔试两个数组的备用数组在数组的交换的时候使用

private float[] mRestoreTwos = null;

然后我们通过x值求出Y的数组

for (int i = 0; i < mWidth; i++) {

mContentOneYs[i] = getYPosition(i, SWINGONE, OFFSETONE, INIT_BASE_HEIGHT1);

mContentTwoys[i] = getYPosition(i, SWINGTWO, OFFSETTWO, INIT_BASE_HEIGHT2);

}

private float getYPosition(int x, int swing, int offset, int baseHeight) {

float cycle = (float) (2 * Math.PI) / mWidth;

return (float) Math.sin(cycle * x + offset) * swing + baseHeight;

}

说明一下这里面的几个值得意思

x代表x值,swing代表这幅高度,offset代表一开始的sin'的角度,baseHeight代表基础高度大小,mWidth代表控件的宽度。这个在获取控件宽度的时候实现就是Onsizechang的时候。

加下来就是我们移动y值了

private void changeRestorePosition() {

if (mWidth != 0) {

mPosition1 = (mPosition1 + STEP1) % mWidth;//循环显示

System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1);

System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1);

mPosition2 = (mPosition2 + STEP2) % mWidth;//循环显示

System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2);

System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2);

}

}

STEP1 和 STEP2 分别代表不同的移动速度

而要绘制出图形就必须把y值和底部连成线然后由mWidht多太哦直线形成一个函数

for (int i = 0; i < mWidth; i++) {

final int x = i;

final float y1 = mRestoreOnes[i];

final float y2 = mRestoreTwos[i];

canvas.drawLine(x, y2, x, mHeight, mPaint2);

canvas.drawLine(x, y1, x, mHeight, mPaint1);

}

最后是不断刷新 由于人眼一般能分辨的是30fps 所以 我这里设置是睡眠0.05秒当然你不怕性能影响的话就直接在OnDraw的时候invalidate();

先面试完整代码

public class WaveView extends View {

private volatile boolean RUNING=true;

private final int INIT_BASE_HEIGHT1 = 300;//基础高度

private final int INIT_BASE_HEIGHT2 = 300;

private int mHeight;

private int mWidth;

private float[] mContentOneYs = null;//这两个代表两条线的y值得数据组

private float[] mContentTwoys = null;

private float[] mRestoreOnes = null;//这两个分笔试两个数组的备用数组在数组的交换的时候使用

private float[] mRestoreTwos = null;

private static final int SWINGONE = 40;//分别代表两个的正弦函数的上下幅度

private static final int SWINGTWO = 80;

private static final int OFFSETONE = 0;//代表一开始的sin 的角度 从 0到360

private static final int OFFSETTWO = 40;

private int mPosition1 = 0;//代表起始高度

private int mPosition2 = 0;

private static final int STEP1 = 5;//这两个分别代表两条线的两个的速率

private static final int STEP2 = 8;

private Paint mPaint1;

private Paint mPaint2;

public WaveView(Context context) {

this(context, null);

}

public WaveView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

mPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);

mPaint1.setColor(Color.parseColor("#AB9DCF"));

mPaint1.setStrokeWidth(4);

mPaint1.setAlpha(125);

mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);

mPaint2.setColor(Color.parseColor("#A2D1F3"));

mPaint2.setStrokeWidth(4);

mPaint2.setAlpha(125);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

if (w != 0 || h != 0 || w != oldw || h != oldh) {

mWidth = w;

mHeight = h;

calculatePoints();

}

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.save();

changeRestorePosition();

for (int i = 0; i < mWidth; i++) {

final int x = i;

final float y1 = mRestoreOnes[i];

final float y2 = mRestoreTwos[i];

canvas.drawLine(x, y2, x, mHeight, mPaint2);

canvas.drawLine(x, y1, x, mHeight, mPaint1);

}

// invalidate();//通过这个来形成循环

}

private void calculatePoints() {

mContentOneYs = new float[mWidth];

mContentTwoys = new float[mWidth];

mRestoreOnes = new float[mWidth];

mRestoreTwos = new float[mWidth];

for (int i = 0; i < mWidth; i++) {

mContentOneYs[i] = getYPosition(i, SWINGONE, OFFSETONE, INIT_BASE_HEIGHT1);

mContentTwoys[i] = getYPosition(i, SWINGTWO, OFFSETTWO, INIT_BASE_HEIGHT2);

}

}

private void changeRestorePosition() {

if (mWidth != 0) {

mPosition1 = (mPosition1 + STEP1) % mWidth;//循环显示

System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1);

System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1);

mPosition2 = (mPosition2 + STEP2) % mWidth;//循环显示

System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2);

System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2);

}

}

private float getYPosition(int x, int swing, int offset, int baseHeight) {

float cycle = (float) (2 * Math.PI) / mWidth;

return (float) Math.sin(cycle * x + offset) * swing + baseHeight;

}

public void startAnimotion()

{

RUNING=true;

final Handler handler=new Handler();

Thread thread=new Thread(new Runnable() {

@Override

public void run() {

while (RUNING)

{

try {

Thread.sleep(50);

} catch (InterruptedException e) {

e.printStackTrace();

}

handler.post(new Runnable() {

@Override

public void run() {

invalidate();

}

});

}

}

});

thread.start();

}

@Override

protected void onDetachedFromWindow() {

RUNING=false;

super.onDetachedFromWindow();

}

}

接下来我们要实现小球

我们只需要设置Paint的模式为DST_OUT,关于Paint的模式请参考

吴小龙

image

代码如下

mPaint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));

mCanvas.drawCircle(mWidth/2,mHeight/2,Math.min(mWidth,mHeight)/2,mPaint2);

canvas.drawBitmap(bitmap,0,0,null);

然后是居中显示 文字

Paint textPaint = new Paint(); // 创建画笔

textPaint.setColor(0xffffffff); // 设置颜色

textPaint.setStyle(Paint.Style.FILL); // 设置样式

textPaint.setTextSize(120);

Rect targetRect = new Rect((mWidth-mHeight)/2, 0,mHeight+(mWidth-mHeight)/2, mHeight);

// textPaint.measureText("",0,1);

Paint.FontMetricsInt fontMetrics = mPaint2.getFontMetricsInt();

int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;

textPaint.setTextAlign(Paint.Align.CENTER);

canvas.drawText(value+"分", targetRect.centerX(), baseline+50, textPaint);

同时我们在xml里给他设置一个background

最后得到的效果如下

GIF3.gif

最后代码如下

public class WaveView extends View {

private int value=80;

private boolean drawCircle=true;

private volatile boolean RUNING=true;

private final int INIT_BASE_HEIGHT1 = 300;//基础高度

private final int INIT_BASE_HEIGHT2 = 300;

private int mHeight;

private int mWidth;

private float[] mContentOneYs = null;//这两个代表两条线的y值得数据组

private float[] mContentTwoys = null;

private float[] mRestoreOnes = null;//这两个分笔试两个数组的备用数组在数组的交换的时候使用

private float[] mRestoreTwos = null;

private static final int SWINGONE = 40;//分别代表两个的正弦函数的上下幅度

private static final int SWINGTWO = 80;

private static final int OFFSETONE = 0;//代表一开始的sin 的角度 从 0到360

private static final int OFFSETTWO = 40;

private int mPosition1 = 0;//代表起始高度

private int mPosition2 = 0;

private static final int STEP1 = 5;//这两个分别代表两条线的两个的速率

private static final int STEP2 = 8;

private Paint mPaint1;

private Paint mPaint2;

private Paint circlePaint;

Bitmap bitmap;

Canvas mCanvas;

public WaveView(Context context) {

this(context, null);

}

public WaveView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

mPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);

mPaint1.setColor(Color.parseColor("#AB9DCF"));

mPaint1.setStrokeWidth(4);

mPaint1.setAlpha(125);

mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);

mPaint2.setColor(Color.parseColor("#A2D1F3"));

mPaint2.setStrokeWidth(4);

mPaint2.setAlpha(125);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

bitmap = Bitmap.createBitmap(getMeasuredWidth(),getMeasuredHeight(), Bitmap.Config.ARGB_8888);

mCanvas = new Canvas(bitmap);

mCanvas.drawColor(Color.WHITE);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

if (w != 0 || h != 0 || w != oldw || h != oldh) {

mWidth = w;

mHeight = h;

calculatePoints();

}

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.save();

init();

changeRestorePosition();

for (int i = 0; i < mWidth; i++) {

final int x = i;

final float y1 = mRestoreOnes[i];

final float y2 = mRestoreTwos[i];

canvas.drawLine(x, y2, x, mHeight, mPaint2);

canvas.drawLine(x, y1, x, mHeight, mPaint1);

}

// invalidate();//通过这个来形成循环

if(drawCircle)

{

Paint textPaint = new Paint(); // 创建画笔

textPaint.setColor(0xffffffff); // 设置颜色

textPaint.setStyle(Paint.Style.FILL); // 设置样式

textPaint.setTextSize(120);

Rect targetRect = new Rect((mWidth-mHeight)/2, 0,mHeight+(mWidth-mHeight)/2, mHeight);

// textPaint.measureText("",0,1);

Paint.FontMetricsInt fontMetrics = mPaint2.getFontMetricsInt();

int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;

textPaint.setTextAlign(Paint.Align.CENTER);

canvas.drawText(value+"分", targetRect.centerX(), baseline+50, textPaint);

}

if (drawCircle ) {

mPaint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));

mCanvas.drawCircle(mWidth/2,mHeight/2,Math.min(mWidth,mHeight)/2,mPaint2);

canvas.drawBitmap(bitmap,0,0,null);

}

}

private void calculatePoints() {

mContentOneYs = new float[mWidth];

mContentTwoys = new float[mWidth];

mRestoreOnes = new float[mWidth];

mRestoreTwos = new float[mWidth];

for (int i = 0; i < mWidth; i++) {

mContentOneYs[i] = getYPosition(i, SWINGONE, OFFSETONE, INIT_BASE_HEIGHT1);

mContentTwoys[i] = getYPosition(i, SWINGTWO, OFFSETTWO, INIT_BASE_HEIGHT2);

}

}

private void changeRestorePosition() {

if (mWidth != 0) {

mPosition1 = (mPosition1 + STEP1) % mWidth;//循环显示

System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1);

System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1);

mPosition2 = (mPosition2 + STEP2) % mWidth;//循环显示

System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2);

System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2);

}

}

private float getYPosition(int x, int swing, int offset, int baseHeight) {

float cycle = (float) (2 * Math.PI) / mWidth;

return (float) Math.sin(cycle * x + offset) * swing + baseHeight;

}

public void startAnimotion()

{

RUNING=true;

final Handler handler=new Handler();

Thread thread=new Thread(new Runnable() {

@Override

public void run() {

while (RUNING)

{

try {

Thread.sleep(50);

} catch (InterruptedException e) {

e.printStackTrace();

}

handler.post(new Runnable() {

@Override

public void run() {

invalidate();

}

});

}

}

});

thread.start();

}

@Override

protected void onDetachedFromWindow() {

RUNING=false;

super.onDetachedFromWindow();

}

}

android多个水波球,Android最简单的方式实现波浪纹和小球相关推荐

  1. android多个水波球,android球形水波百分比控件代码

    本文主要介绍的是一个球形水波的百分比控件,市面上有各种形形色色的百分比控件,我一直觉得水波是最炫的,UI给了我这个机会,然而网上搜了一大堆,不是太复杂,代码太多(反正我是调不出效果来),就是有瑕疵的, ...

  2. android 布局收缩成球,Android使用Material Design实现悬浮按钮

    前言 ​ 本文是对<Android第一行代码>第十二章<最佳UI体验--Material Design实战>中关于悬浮按钮实现的学习和记录,主要内容包括-- FloatingA ...

  3. Android 自定义水波球清理内存的悬浮窗小工具

    一.概述 现在一些手机管家都会有一个用来清理内存的悬浮窗小工具,感觉挺实用的,就自己做了一个.首先介绍一下这个工具的功能,除了可以清理内存,还有调节手机屏幕亮度.手电筒.无线网.移动数据.蓝牙.GPS ...

  4. android悬浮球代码,Android 仿360悬浮球与加速球

    先来看一张动态图 昨天跟着视频学了如何自定义View并做成仿360悬浮球与加速球的样式 可以看出来,做成的效果有: 点击按钮后退出Activity,呈现一个圆形的悬浮球,可以随意拖动并会自动依靠到屏幕 ...

  5. android 悬浮球动画,Android 仿360悬浮球与加速球

    先来看一张动态图 昨天跟着视频学了如何自定义View并做成仿360悬浮球与加速球的样式 可以看出来,做成的效果有: 点击按钮后退出Activity,呈现一个圆形的悬浮球,可以随意拖动并会自动依靠到屏幕 ...

  6. android 说话水波动画,Android实用View——水波动画效果多种实现方式详解

    原标题:Android实用View--水波动画效果多种实现方式详解 这次给大家带来的是一篇关于自定义View实现水波动画效果的文章,其实在去年项目中使用过类似的动画,当时就自定义View也实现了预期的 ...

  7. android 代码浏览,Webview实现android简单的浏览器实例代码

    WebView是Android中一个非常实用的组件,它和Safai.Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数据的方式便捷地展现软件的界面,下面通过本文给大家介绍Webv ...

  8. 【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位网友补充完善...

    链接地址:http://www.tuicool.com/articles/jyA3MrU 时间 2015-01-05 10:08:18  我是程序猿,我为自己代言 原文  http://blog.cs ...

  9. Android中的AsyncTask异步任务的简单实例

    在  Android中的AsyncTask异步任务的简单介绍 一文中,已经对 安卓 异步任务操作做了简单的介绍,这里,直接将上文中的异步任务做了一个实例,实现异步操作更新UI线程,相比开启子线程更新来 ...

最新文章

  1. 报名 | 四场直播讲透AI芯片的应用与挑战、剖析技术难点,芯片的所有知识点都在这了...
  2. 同等学力计算机综合难吗,报考2018年同等学力申硕计算机在职研究生毕业很困难吗...
  3. 处理Xcode8输出无用的Log信息
  4. Akka框架——第一节:并发编程简介
  5. 数组去重(JavaScript)先从网上整理一波,待验证
  6. 如何判断两个平面相交_七年级下册相交线与平行线全章节复习
  7. 小蚂蚁学习PHP性能优化(2)--PHP语言级性能优化
  8. 自己在总结前人经验下弄的几个opencv封装函数
  9. asp.net获取浏览器的唯一标识_vue单页面应用如何在微信浏览器里进行网页授权获取用户信息
  10. 在input标签里只能输入数字
  11. 几款远程登录软件的对比
  12. QXRService:基于高通QXRService获取SLAM Camera图像
  13. 老程序员告诉你人工智能工程师与Python工程师有什么区别?
  14. 自供电面包板----面包板伴侣项目介绍
  15. js实现键盘数字输入
  16. 小学生该学什么编程语言入门?
  17. 如何使用Python发送库存更新
  18. K8S 快速入门(十二)实战篇:配置 ConfigMapSecret
  19. 五个步骤打通电商平台运营思路
  20. matlab高精度工具箱,[转载]高精度捷联惯性导航系统Matlab工具箱

热门文章

  1. SA-SSD环境搭建——血与泪的教训
  2. moco工具第一个Demo入门
  3. c语言中求二次函数的根,二次函数求根公式法
  4. java pdfbox_Java使用PDFBox开发包实现对PDF文档内容编辑与保存
  5. 凸集、凸函数及其充分必要条件
  6. 与雅虎专利战 微软助阵Facebook
  7. GB28181视频监控管理平台LiveGBS如何指定获取摄像头子码流或者主码流
  8. [c语言]c语言中a++ ++a在加法运算中和printf函数中的运算顺序(初学者版)
  9. windows无法配置此无线连接的无线网络
  10. 如果梅西碰到这套阵容,还能夺冠吗?