android多个水波球,Android最简单的方式实现波浪纹和小球
我们先看一下效果
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最简单的方式实现波浪纹和小球相关推荐
- android多个水波球,android球形水波百分比控件代码
本文主要介绍的是一个球形水波的百分比控件,市面上有各种形形色色的百分比控件,我一直觉得水波是最炫的,UI给了我这个机会,然而网上搜了一大堆,不是太复杂,代码太多(反正我是调不出效果来),就是有瑕疵的, ...
- android 布局收缩成球,Android使用Material Design实现悬浮按钮
前言 本文是对<Android第一行代码>第十二章<最佳UI体验--Material Design实战>中关于悬浮按钮实现的学习和记录,主要内容包括-- FloatingA ...
- Android 自定义水波球清理内存的悬浮窗小工具
一.概述 现在一些手机管家都会有一个用来清理内存的悬浮窗小工具,感觉挺实用的,就自己做了一个.首先介绍一下这个工具的功能,除了可以清理内存,还有调节手机屏幕亮度.手电筒.无线网.移动数据.蓝牙.GPS ...
- android悬浮球代码,Android 仿360悬浮球与加速球
先来看一张动态图 昨天跟着视频学了如何自定义View并做成仿360悬浮球与加速球的样式 可以看出来,做成的效果有: 点击按钮后退出Activity,呈现一个圆形的悬浮球,可以随意拖动并会自动依靠到屏幕 ...
- android 悬浮球动画,Android 仿360悬浮球与加速球
先来看一张动态图 昨天跟着视频学了如何自定义View并做成仿360悬浮球与加速球的样式 可以看出来,做成的效果有: 点击按钮后退出Activity,呈现一个圆形的悬浮球,可以随意拖动并会自动依靠到屏幕 ...
- android 说话水波动画,Android实用View——水波动画效果多种实现方式详解
原标题:Android实用View--水波动画效果多种实现方式详解 这次给大家带来的是一篇关于自定义View实现水波动画效果的文章,其实在去年项目中使用过类似的动画,当时就自定义View也实现了预期的 ...
- android 代码浏览,Webview实现android简单的浏览器实例代码
WebView是Android中一个非常实用的组件,它和Safai.Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数据的方式便捷地展现软件的界面,下面通过本文给大家介绍Webv ...
- 【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位网友补充完善...
链接地址:http://www.tuicool.com/articles/jyA3MrU 时间 2015-01-05 10:08:18 我是程序猿,我为自己代言 原文 http://blog.cs ...
- Android中的AsyncTask异步任务的简单实例
在 Android中的AsyncTask异步任务的简单介绍 一文中,已经对 安卓 异步任务操作做了简单的介绍,这里,直接将上文中的异步任务做了一个实例,实现异步操作更新UI线程,相比开启子线程更新来 ...
最新文章
- 报名 | 四场直播讲透AI芯片的应用与挑战、剖析技术难点,芯片的所有知识点都在这了...
- 同等学力计算机综合难吗,报考2018年同等学力申硕计算机在职研究生毕业很困难吗...
- 处理Xcode8输出无用的Log信息
- Akka框架——第一节:并发编程简介
- 数组去重(JavaScript)先从网上整理一波,待验证
- 如何判断两个平面相交_七年级下册相交线与平行线全章节复习
- 小蚂蚁学习PHP性能优化(2)--PHP语言级性能优化
- 自己在总结前人经验下弄的几个opencv封装函数
- asp.net获取浏览器的唯一标识_vue单页面应用如何在微信浏览器里进行网页授权获取用户信息
- 在input标签里只能输入数字
- 几款远程登录软件的对比
- QXRService:基于高通QXRService获取SLAM Camera图像
- 老程序员告诉你人工智能工程师与Python工程师有什么区别?
- 自供电面包板----面包板伴侣项目介绍
- js实现键盘数字输入
- 小学生该学什么编程语言入门?
- 如何使用Python发送库存更新
- K8S 快速入门(十二)实战篇:配置 ConfigMapSecret
- 五个步骤打通电商平台运营思路
- matlab高精度工具箱,[转载]高精度捷联惯性导航系统Matlab工具箱
热门文章
- SA-SSD环境搭建——血与泪的教训
- moco工具第一个Demo入门
- c语言中求二次函数的根,二次函数求根公式法
- java pdfbox_Java使用PDFBox开发包实现对PDF文档内容编辑与保存
- 凸集、凸函数及其充分必要条件
- 与雅虎专利战 微软助阵Facebook
- GB28181视频监控管理平台LiveGBS如何指定获取摄像头子码流或者主码流
- [c语言]c语言中a++ ++a在加法运算中和printf函数中的运算顺序(初学者版)
- windows无法配置此无线连接的无线网络
- 如果梅西碰到这套阵容,还能夺冠吗?