三角函数之美-水波纹载入LoadingView
一、前言
学习是要总结的。近期几天学习了画图相关的,可是使用的机会较少,如今又快要遗忘了,这次看了水波纹的绘制。认为十分有意思,还是 把实现的方法记录下来。技术无他,为手熟尔。还是要多练习,空淡误国,实干兴邦,让我们看看今天的三角函数之美吧。
二、概述
肯定大家对中学学习的三角函数都不陌生吧。只是学习的sin、cos是超越函数一类函数。是初等函数的一种,借用维基百科的一张图:
一个完整的正弦函数应该是这种:>y=Asin(ωx+φ)+h,A决定峰值,ω决定周期。φ表示初相位,h表示y轴的位置。在Android我们使用通常是Math.sin(30*Math.PI/180)这种形式,我原来搞不懂这样写的含义。后来才明确Math.PI就是π。π即180度。所以上述式子相当于sin(π/6)=1/2,在中学我们通常是sin(30°)=1/2,把sin(x)中的x赋值为角度,而在计算机语言x通常是弧度。
这个流量界面就是通过sin函数曲线不断改变x位置绘制而来,实现的方式肯定也还有其他的方法,通过绘制贝塞尔曲线也有实现的案例。我们将通过样例逐渐对水波纹loadingview绘制,好了不多说了,手把手带你一步一步实现美丽炫酷的loading水波纹效果。
三、波浪控件的实现
首先我们先实现波浪控件的绘制:
先计算坐标点:
//这里我们以view的总宽度为周期,y = a * sin(2π) + b
for (int i = 0; i < mTotalWidth; i++){
mPointY[i] = (float) (20 * (Math.sin( 2 * Math.PI * i / w)));
}
绘制曲线
for (int i = 0;i < mTotalWidth; i++){
canvas.drawLine(i,mTotalHeight - mDaymicPointY[i] - 300,i,mTotalHeight,mPaint);
}
这里减去300仅仅是为了控制在Y轴上的位置,我们能够动态设置一个数值。在view上下移动。从而达到流量界面。我们先一步一步来。
控制移动
//改变两条波纹的移动点
mXoffset += X_SPEED;
//假设已经移动到末尾处,则到头又一次移动
if(mXoffset > mTotalWidth){
mXoffset = 0;
}
// 超出屏幕的挪到前面,mXoffset表示第一条水波纹要移动的距离
int yIntelrval = mPointY.length - mXoffset;
//使用System.arraycopy方式又一次填充第一条波纹的数据
System.arraycopy(mPointY, 0, mDaymicPointY, mXoffset, yIntelrval);
System.arraycopy(mPointY, yIntelrval, mDaymicPointY, 0, mXoffset);
如今你会发现一个简单的水波纹效果出来了,例如以下图所看到的:
你会发现这个水波纹跟我们的效果还是有些差距。别急,我们还有这个类PorterDuffXfermode,能够实现与所绘制的图像按一定规则进行混合,形成新的像素值,那么我们就能够先画一个水波纹效果,然后在画一个圆,使用以下这幅神图进行混合,你会发现奇迹的,PorterDuffXfermode的相关使用能够參考这边博客:
Android中Canvas画图之PorterDuffXfermode使用及工作原理具体解释
使用哪种规则呢,自己找找呗,都是进行某种规则进行混合的,我找到了,使用的是SrcIn,就能够进行混合实现效果了
如今就是这种效果,我们在加一个seekbar。拖动显示效果。基本上就能够出现这个波浪loading效果了
int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
canvas.drawCircle(mTotalWidth / 2, mTotalHeight / 2, mTotalWidth / 2, mCriclePaint);
//设置颜色混合模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//高减去宽除以2使水波纹底部在圆底部。动态改变percent值,在Y轴上变化
for (int i = 0; i < mTotalWidth; i++) {
canvas.drawLine(i, mTotalHeight - mDaymicPointY[i] - (mTotalHeight - mTotalWidth) / 2 - percent * mTotalWidth / 100, i, mTotalHeight - (mTotalHeight - mTotalWidth) / 2, mPaint);
}
//最后将画笔去除Xfermode
mPaint.setXfermode(null);
canvas.restoreToCount(layerId);
效果例如以下图所看到的
咦,说好的明明是水波纹绿颜色呢,怎么变得浅了很多,硬件加速会对效果有影响的, Android从3.0(API Level 11)開始。在绘制View的时候支持硬件加速,充分利用GPU的特性,使得绘制更加平滑。可是会多消耗一些内存。
提供了4个方面打开或者关闭硬件加速,这里也提一下:
1.Application级别:
<applicationandroid:hardwareAccelerated="true" ...>
2.Activity级别:
<activity android:hardwareAccelerated="false" ...>
3.Window级别:
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
注:Android还不支持在Window级别关闭硬件加速。
4.View级别:
myView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
注:Android还不支持在View级别开启硬件加速。
我们直接在application以下全局关闭硬件加速就可以,以下的效果就是这种:
我贴下所有实现过程的代码:
public class WaveView extends View {
private Paint mPaint, mCriclePaint,mTextPaint;
// 倾斜或旋转、高速变化,当在屏幕上画一条直线时, 横竖不会出现锯齿,
// 可是当斜着画时, 就会出现锯齿的效果,所以须要设置抗锯齿
private DrawFilter mDrawFilter;
private int mTotalHeight, mTotalWidth;
private int mXoffset = 0;
private float[] mPointY;
private float[] mDaymicPointY;
//波浪线移动速度
private static final int X_SPEED = 20;
private int percent;
public void setPercent(int percent) {
this.percent = percent;
}
public WaveView(Context context) {
super(context);
init();
}
public WaveView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
//图片线条(通用)的抗锯齿须要另外设置
mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
//实例化一个画笔
mPaint = new Paint();
//去除画笔锯齿
mPaint.setAntiAlias(true);
//设置画笔风格为实线
mPaint.setStyle(Paint.Style.FILL);
//设置画笔颜色
mPaint.setColor(Color.GREEN);
//实例化圆的画笔
mCriclePaint = new Paint(mPaint);
mCriclePaint.setColor(Color.parseColor("#88dddddd"));
mCriclePaint.setAlpha(255);
//实例化文字画笔
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//去除锯齿
canvas.setDrawFilter(mDrawFilter);
runWave();
int canvasWidth = canvas.getWidth();
int canvasHeight = canvas.getHeight();
int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
canvas.drawCircle(mTotalWidth / 2, mTotalHeight / 2, mTotalWidth / 2, mCriclePaint);
//设置颜色混合模式
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//高减去宽除以2使水波纹底部在圆底部,动态改变percent值,在Y轴上变化
for (int i = 0; i < mTotalWidth; i++) {
canvas.drawLine(i, mTotalHeight - mDaymicPointY[i] - (mTotalHeight - mTotalWidth) / 2 - percent * mTotalWidth / 100, i, mTotalHeight - (mTotalHeight - mTotalWidth) / 2, mPaint);
}
//最后将画笔去除Xfermode
mPaint.setXfermode(null);
canvas.restoreToCount(layerId);
//改变两条波纹的移动点
mXoffset += X_SPEED;
//假设已经移动到末尾处。则到头又一次移动
if (mXoffset > mTotalWidth) {
mXoffset = 0;
}
String text = percent + "%";
mTextPaint.setTextSize(80);
float textLength = mTextPaint.measureText(text);
canvas.drawText(text,(mTotalWidth - textLength) / 2,mTotalHeight / 2 - 20,mTextPaint);
//引起view重绘
postInvalidateDelayed(300);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mTotalHeight = h;
mTotalWidth = w;
//数组的长度为view的宽度
mPointY = new float[w];
mDaymicPointY = new float[w];
//这里我们以view的总宽度为周期,y = a * sin(2π) + b
for (int i = 0; i < mTotalWidth; i++) {
mPointY[i] = (float) (20 * (Math.sin(2 * Math.PI * i / w)));
}
}
private void runWave() {
// 超出屏幕的挪到前面。mXoffset表示第一条水波纹要移动的距离
int yIntelrval = mPointY.length - mXoffset;
//使用System.arraycopy方式又一次填充第一条波纹的数据
System.arraycopy(mPointY, 0, mDaymicPointY, mXoffset, yIntelrval);
System.arraycopy(mPointY, yIntelrval, mDaymicPointY, 0, mXoffset);
}
}
上面就是实现的所有代码了,都有凝视。相信大家能看懂,事实上实现这些效果还是非常easy的,可是我们还有很多扩展的地方,做成一个网络载入的等待动画,或者做成一个下载的的进度,等待大家自己去实现。
源代码:下载地址猛戳
三角函数之美-水波纹载入LoadingView的更多相关文章
- 手把手教你画一个 逼格满满圆形水波纹loadingview Android
才没有完结呢o( ̄︶ ̄)n .大家好,这里是番外篇. 拜读了爱哥的博客,又学到不少东西.爱哥曾经说过: 要站在巨人的丁丁上. 那么今天,我们就站在爱哥的丁丁上来学习制作一款自定义view(开个玩笑,爱 ...
- OC语言编写:为视图添加丝滑的水波纹
先看一下最终效果图: 首先我们可以把如此丝滑的水波纹拆分一下下: 一条规律的曲线. 曲线匀速向右移动. 曲线下方的位置用颜色填充. 于是先来一条曲线吧. 对于需要产生波动如此规律的曲线,我们首先想到的 ...
- android 5.0 默认水波纹背景属性,可设置不论什么View
actionBarItemBackground 5.0以上超出边界圆形水波纹 selectableItemBackground 5.0以上边界内圆形水波纹 这两个属性在5.0下面是默认的灰色效果 ...
- jquery ripples水波纹效果( 涟漪效果)
这个效果是我从bootstrap-material-design上面分离下来的,bootstrap-material-design的一些组件样式我不太不喜欢,但是非常喜欢这个水波纹效果,所以就有了这篇 ...
- 如何使用 HTML5 Canvas 制作水波纹效果
今天,我们继续分享 JavaScript 实现的效果例子,这篇文章会介绍使用 JavaScript 实现水波纹效果.水波效果以图片为背景,点击图片任意位置都会触发.有时候,我们使用普通的 Javasc ...
- 兼容Android的水波纹效果
Android的水波纹效果只有高版本才有,我们希望自己的应用在低版本用低版本的阴影,高版本用水波纹,这怎么做呢?其实,只要分drawable和drawablev21两个文件夹就好了. 普通情况下的se ...
- android自定义控件(4)-自定义水波纹效果
一.实现单击出现水波纹单圈效果: 照例来说,还是一个自定义控件,观察这个效果,发现应该需要重写onTouchEvent和onDraw方法,通过在onTouchEvent中获取触摸的坐标,然后以这个坐标 ...
- android 5.0 水波纹 实现
1. 定义一个普通圆角背景的xml; rounded_corners.xml <?xml version="1.0" encoding="utf-8"?& ...
- VC_MFC水波纹控件,开源
代码和效果图: https://github.com/wjx0912/MfcWaterEffect 集成以下5个文件即可: watereffect\DIB.hwatereffect\DIB.cppwa ...
随机推荐
- poj 2663 Tri Tiling (状压dp+多米诺骨牌问题+滚动数组反思)
本来直接一波状压dpAC的 #include<cstdio> #include<cstring> #include<algorithm> #define REP(i ...
- 紫书 例题7-14 UVa 1602(搜索+STL+打表)
这道题想了很久不知道怎么设置状态,怎么拓展,怎么判重, 最后看了这哥们的博客 终于明白了. https://blog.csdn.net/u014800748/article/details/47400 ...
- 《你又怎么了我错了行了吧》第九次团队作业:Beta冲刺与验收准备
项目 内容 这个作业属于哪个课程 软件工程 这个作业的要求在哪里 实验十三 团队作业9 团队名称 你又怎么了我错了行了吧 作业学习目标 (1)掌握软件黑盒测试技术: (2)学会编制软件项目总结PPT. ...
- 20130910.Windows上安装和配置MongoDB
官方文档:http://docs.mongodb.org/manual/tutorial/ 1.下载软件 http://www.mongodb.org/downloads 2.解压 解压后进入bin目 ...
- XML 解析---dom解析和sax解析
眼下XML解析的方法主要用两种: 1.dom解析:(Document Object Model.即文档对象模型)是W3C组织推荐的解析XML的一种方式. 使用dom解析XML文档,该解析器会先把XML ...
- MapReduce(十六): 写数据到HDFS的源代码分析
1) LineRecordWriter负责把Key,Value的形式把数据写入到DFSOutputStream watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZ ...
- Request的getParameter和getAttribute方法的差别
HttpServletRequest.getParameter("modelName");能取到想要的modelObject吗?经过測试之后.发现是不能的. 后来想想.其它道理挺简 ...
- JAXB xml与javaBean的转换
转自:https://blog.csdn.net/lydong_/article/details/79812626 `1. 1.不认识到犯错,然后得到永久的教训. 也不是所谓的教训吧,真正的教训来自于 ...
- 简单的beego分页功能代码
一个简单的beego分页小插件(源代码在最下面): 支持条件查询 支持参数保留 支持自定义css样式 支持表/视图 支持参数自定义 默认为pno 支持定义生成链接的个数 使用方式: 1)action中 ...
- vue keep-alive保存路由状态2 (高级用法,接上篇)
接上篇 https://www.cnblogs.com/wangmaoling/p/9803960.html 本文很长,请耐心看完分析. 4.高级用法,指定从什么组件进入才缓存,以及销毁缓存:先介绍我 ...