如何给Imageview设置水波纹效果
水波纹效果:
1标准正余弦水波纹;
2非标准圆形液柱水波纹;
虽说都是水波纹,但两者在实现上差异是比较大的,一个通过正余弦函数模拟水波纹效果,另外一个会运用到图像的混合模式(PorterDuffXfermode);
先看效果:
自定义View根据实际情况可以选择继承自View、TextView、ImageView或其他
这次的实现我们都选择继承view,在实现的过程中我们需要关注如下几个方法:
1onMeasure():最先回调,用于控件的测量;
2onSizeChanged():在onMeasure后面回调,可以拿到view的宽高等数据,在横竖屏切换时也会回调;
3onDraw():真正的绘制部分,绘制的代码都写到这里面;
既然如此,我们先复写这三个方法,然后来实现如上两个效果;
一:标准正余弦水波纹
这种水波纹可以用具体函数模拟出具体的轨迹,所以思路基本如下:
1确定水波函数方程
2根据函数方程得出每一个波纹上点的坐标;
3将水波进行平移,即将水波上的点不断的移动;
4不断的重新绘制,生成动态水波纹;
有了上面的思路,我们一步一步进行实现:
正余弦函数方程为:
y=_sin(wx+b)+h,这个公式里:w影响周期,A影响振幅,h影响y位置,b为初相;
根据上面的方程选取自己觉得中意的波纹效果,确定对应参数的取值;
然后根据确定好的方程得出所有的方程上y的数值,并将所有y值保存在数组里:
//_芷诙ㄎ_iew总宽度_
mCycleFactorW=(float)(2_/_TotalWidth);_
//__iew总宽度得出所有对应的y值_
for(int_=0;_<_TotalWidth;_++)__
__mYPositions[i]=(float)(STRETCH_FACTOR_A(mCycleFactorW_)+_FFSET_Y);_
}_
根据得出的所有y值,则可以在onDraw中通过如下代码绘制两条静态波纹:
for(int_=0;_<_TotalWidth;_++)__
___//_400只是为了控制波纹绘制的y的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果_
___//_嬷频谝惶跛ㄎ_
___(i,_TotalHeight-_ResetOneYPositions[i]-400,_,_
_______mTotalHeight,_
_______mWavePaint);_
___//_嬷频诙跛ㄎ_
___(i,_TotalHeight-_ResetTwoYPositions[i]-400,_,_
_______mTotalHeight,_
_______mWavePaint);_
_}_
这种方式类似于数学里面的细分法,一条波纹,如果横向以一个像素点为单位进行细分,则形成view总宽度条直线,并且每条直线的起点和终点我们都能知道,在此基础上我们只需要循环绘制出所有细分出来的直线(直线都是纵向的),则形成了一条静态的水波纹;
接下来我们让水波纹动起来,之前用了一个数组保存了所有的y值点,有两条水波纹,再利用两个同样大小的数组来保存两条波纹的y值数据,并不断的去改变这两个数组中的数据:
_rivate_oid_esetPositonY()__
__//_XOneOffset代表当前第一条水波纹要移动的距离_
__int_OneInterval=_-_XOneOffset;_
__//_褂梅绞街匦绿畛涞谝惶醪ㄎ频氖_
__(mYPositions,_XOneOffset,_ResetOneYPositions,0,_OneInterval);_
__(mYPositions,0,_ResetOneYPositions,_OneInterval,_XOneOffset);_
__int_TwoInterval=_-_XTwoOffset;_
__(mYPositions,_XTwoOffset,_ResetTwoYPositions,0,_
______yTwoInterval);_
__(mYPositions,0,_ResetTwoYPositions,_TwoInterval,_XTwoOffset);_
}_
如此下来只要不断的改变这两个数组的数据,然后不断刷新,即可生成动态水波纹了;
刷新可以调用invalidate()或postInvalidate(),区别在于后者可以在子线程中更新UI
整体代码如下:
package;
import;
import;
import;
import;
import;
import;
import;
import;
import;
public_lass_ynamicWave_xtends_iew_
__//_ㄎ蒲丈
__private_tatic_inal_nt_AVE_PAINT_COLOR=0x880000aa;
__//_=_sin(wx+b)+h
__private_tatic_inal_loat_TRETCH_FACTOR_A=20;
__private_tatic_inal_nt_FFSET_Y=0;
__//_谝惶跛ㄒ贫俣
__private_tatic_inal_nt_RANSLATE_X_SPEED_ONE=7;
__//_诙跛ㄒ贫俣
__private_tatic_inal_nt_RANSLATE_X_SPEED_TWO=5;
__private_loat_CycleFactorW;
__private_nt_TotalWidth,_TotalHeight;
__private_loat[]_YPositions;
__private_loat[]_ResetOneYPositions;
__private_loat[]_ResetTwoYPositions;
__private_nt_XOffsetSpeedOne;
__private_nt_XOffsetSpeedTwo;
__private_nt_XOneOffset;
__private_nt_XTwoOffset;
__private_aint_WavePaint;
__private_rawFilter_DrawFilter;
__public_ynamicWave(Context_ontext,_ttributeSet_ttrs)_
____super(context,_ttrs);
____//__p转化为px,用于控制不同分辨率上移动速度基本一致
____mXOffsetSpeedOne=(context,_RANSLATE_X_SPEED_ONE);
____mXOffsetSpeedTwo=(context,_RANSLATE_X_SPEED_TWO);
____//_跏蓟嬷撇ㄎ频幕
____mWavePaint=_ew_aint();
____//_コ示獬
____(true);
____//_柚梅绺裎迪
____();
____//_柚没恃丈
____(WAVE_PAINT_COLOR);
____mDrawFilter=_ew_aintFlagsDrawFilter(0,_ALIAS_FLAG__BITMAP_FLAG);
__}
__@Override
__protected_oid_nDraw(Canvas_anvas)_
____(canvas);
____//__anvas层面去除绘制时锯齿
____(mDrawFilter);
____resetPositonY();
____for(int_=0;_<_TotalWidth;_++)_
______//_400只是为了控制波纹绘制的y的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果
______//_嬷频谝惶跛ㄎ
______(i,_TotalHeight-_ResetOneYPositions[i]-400,_,
__________mTotalHeight,
__________mWavePaint);
______//_嬷频诙跛ㄎ
______(i,_TotalHeight-_ResetTwoYPositions[i]-400,_,
__________mTotalHeight,
__________mWavePaint);
____}
____//_谋淞教醪ㄎ频囊贫
____mXOneOffset+=_XOffsetSpeedOne;
____mXTwoOffset+=_XOffsetSpeedTwo;
____//_绻丫贫浇嵛泊,则重头记录
____if(mXOneOffset>=_TotalWidth)_
______mXOneOffset=0;
____}
____if(mXTwoOffset>_TotalWidth)_
______mXTwoOffset=0;
____}
____//_view重绘,一般可以考虑延迟20-30ms重绘,空出时间片
____postInvalidate();
__}
__private_oid_esetPositonY()_
____//_XOneOffset代表当前第一条水波纹要移动的距离
____int_OneInterval=_-_XOneOffset;
____//_褂梅绞街匦绿畛涞谝惶醪ㄎ频氖
____(mYPositions,_XOneOffset,_ResetOneYPositions,0,_OneInterval);
____(mYPositions,0,_ResetOneYPositions,_OneInterval,_XOneOffset);
____int_TwoInterval=_-_XTwoOffset;
____(mYPositions,_XTwoOffset,_ResetTwoYPositions,0,
________yTwoInterval);
____(mYPositions,0,_ResetTwoYPositions,_TwoInterval,_XTwoOffset);
__}
__@Override
__protected_oid_nSizeChanged(int_,_nt_,_nt_ldw,_nt_ldh)_
____(w,_,_ldw,_ldh);
____//_锹枷_iew的宽高
____mTotalWidth=_;
____mTotalHeight=_;
____//_糜诒4嬖疾ㄎ频_值
____mYPositions=_ew_loat[mTotalWidth];
____//_糜诒4娌ㄎ埔坏_值
____mResetOneYPositions=_ew_loat[mTotalWidth];
____//_糜诒4娌ㄎ贫_值
____mResetTwoYPositions=_ew_loat[mTotalWidth];
____//_芷诙ㄎ_iew总宽度
____mCycleFactorW=(float)(2_/_TotalWidth);
____//__iew总宽度得出所有对应的y值
____for(int_=0;_<_TotalWidth;_++)_
______mYPositions[i]=(float)(STRETCH_FACTOR_A(mCycleFactorW_)+_FFSET_Y);
____}
__}
}
二:非标准圆形液柱水波纹
前面的波形使用函数模拟,这个我们换种方式,采用图进行实现,先用PS整张不像波纹的波纹图;
为了衔接紧密,首尾都比较平,并高度一致;
思路:
1使用一个圆形图作为遮罩过滤波形图;
2平移波纹图,即不断改变绘制的波纹图的区域,即srcRect;
3当一个周期绘制完,则从波纹图的最前面重新计算;_
全部代码如下
__//_跏蓟_itmap
__private_oid_nitBitmap()_
____mSrcBitmap=((BitmapDrawable)
________getBitmap();
____mMaskBitmap=((BitmapDrawable)_etResources()getDrawable(
________R_500))
________getBitmap();
__}
__//_跏蓟_aint
__private_oid_nitPaint()_
____mBitmapPaint=_ew_aint();
____//_蓝抖
____(true);
____//_敉枷窆
____(true);
____mPicPaint=_ew_aint(_ALIAS_FLAG);
____(true);
____();
__}
__@Override
__protected_oid_nSizeChanged(int_,_nt_,_nt_ldw,_nt_ldh)_
____(w,_,_ldw,_ldh);
____mTotalWidth=_;
____mTotalHeight=_;
____mCenterX=_TotalWidth/2;
____mCenterY=_TotalHeight/2;
____mSrcRect=_ew_ect();
____mDestRect=_ew_ect(0,0,_TotalWidth,_TotalHeight);
____int_askWidth=();
____int_askHeight=();
____mMaskSrcRect=_ew_ect(0,0,_askWidth,_askHeight);
____mMaskDestRect=_ew_ect(0,0,_TotalWidth,_TotalHeight);
__}
}
如何给Imageview设置水波纹效果假设名是myImage@用[buttonSetBackgroundImage:[UIImageimageNamed:@"myImage"]];就可以了。多少个button公用一张都是可以的,不会出现冲突问题,系统会根据这个生成N个实例对象。
摩托车化油器看起来非常复杂,但是只要掌握一些原理,你就能把你的摩托车调整到最佳状态。所有的化油器都是在大气压力的基本原理下工作的。大气压是一种对万事万物施加压力的强大力量。它会有细微变化,但是通常情况下每平方英寸有十五磅压力(psi)。这意味这大气压对任何事物的压力都是每平方英寸十五磅压力。通过改变引擎和化油器内的大气压,我们能够改变压力并使燃料和空气通过化油器流动。
大气压力会从高压扩散到低压。当二冲程引擎的活塞处于上止点(或四冲程引擎的活塞处于下止点)时,在曲轴箱里的活塞下面(四冲程引擎的活塞上面)会形成一个低压。同时这个低压也会引起化油器里的低压。因为在引擎和化油器外面的压力比较高,空气将会冲进化油器并且进入引擎直到压力被均衡。通过化油器流动的空气将会带动燃料,燃料将会与空气混合。
在化油器里面是一段喉管,见1。喉管是在化油器里面迫使空气加速通过的收缩部分。突然变窄的河流能被用来举例说明发生进化油器里面的情形。河水在靠近变窄的河岸时会加快速度,如果河岸连续变窄的话将会更快。相同的事情发生在化油器里面。加速流动的空气将会引起化油器里面的大气压力降低。空气流动速度越快,化油器里面的压力越低。藉由在喉管里面放置管子,我们能利用低压将燃料混入气流。
大多数的摩托车化油器通道被风门位置而不是引擎转速控制。大多数摩托车化油器里面有五个主要调节系统。这些调节系统互相影响,他们是:
.怠速通道
.怠速量孔
.主喷嘴和油针
.主量孔
.阻风门通道
怠速通道有二个可调节部分,2。节流阀空气螺丝和怠速量孔。
空气螺丝可以被定位于化油器的背面或者前面。如果空气螺丝位于背面,它是用来调节多少空气进入节流阀系统的。如果空气螺丝被旋入,它减少空气量并加浓混合气。如果它被旋出,将打开更多通道并允许较多的空气进入通道导致混合气变稀。如果空气螺丝位于前面,它是调节燃料的供给。如果它被旋入混合气将会变稀,如果它被旋出混合气则变浓。如果为了获得最佳怠速和性能不得不将空气螺丝旋转两圈以上,则必须更换更小或更大尺寸的怠速量孔。
怠速量孔是在油门开度低时供给大部份燃料的部件。它里面有一个用来限制燃料流动的小孔。怠速空气螺丝和怠速量孔都影响从怠速到1/4左右油门开度的汽化作用。
柱塞在1/8到1/2油门开度之间影响汽化作用。它尤其在1/8到1/4(油门开度)之间影响(汽化作用),在1/4到1/2(油门开度)之间影响较小。柱塞具有不同尺寸规格,而且规格是由它的后背部切口的大小决定的,3。切口愈大,混合气会比较稀(因为较多的空气被允许通过),切口愈小混合气将比较浓。柱塞上有数字用以说明切口是多少。如果在柱塞上有个数字3,说明它有3毫米的切口,当那个数字是1的时候说明有1毫米的切口(混合气将会比数字为3的浓)。
油针和主喷嘴影响从1/4到3/4油门开度的汽化作用。油针是一根控制多少燃料可以被吸入化油器喉管的长锥形杆。锥形愈细,混合气愈浓。锥形愈粗,由于较粗的锥形不会象较细的锥形那样允许较多的燃料进入化油器,所以混合气愈稀。锥形被设计得非常精密,用来在不同的油门开度给不同的混合气。油针的顶部开有若干凹槽。一个卡箍装在这些凹槽之一上面,用来防止它从柱塞上掉落或者位移。卡箍的位置能被改变,使引擎运行在更浓或稀(的混合气状态),4。如果引擎需要较稀的混合气,卡箍应该被移到较高位置。这将会使油针更深地进入主喷嘴并导致较少的燃料通过它流动。如果卡箍被降低,油针被提起,混合气将会较浓。
主喷嘴是油针滑动进出的地方。仰赖主喷嘴的内部直径,它将会影响油针。主喷嘴和油针一起作工控制在3/4到1/8(油门开度)范围之间的燃料流。在此范围间的大部份调节是对油针进行,而不是主喷嘴进行的。
主量孔控制从3/4油门开度到油门全开之间的燃料流,5。一旦油门开度达到一定程度,油针被从主喷嘴中拉出足够高度,此时主量孔开始调节燃料流量。主量孔具有不同尺寸,较大的孔能使较多燃料通过(混合气较浓)主量孔上数字较高的会比数字较小的孔具有较浓的空气/燃料混合物。
阻风门系统被用于启动冷机。由于燃料在冷机中因为凝结作用会黏在气缸壁上,混合气对于启动引擎来说是太稀了。阻风门系统将会把燃料加入引擎用以补偿被凝结在气缸壁上的燃料。一旦引擎变暖,凝结将不是问题,而且阻风门不再被需要。
空气/燃料混合物必须适应引擎的需求而变化。理想的空气/燃料比是147克的空气/1克的燃料。当引擎正在运行时这个理想比只能在极短期间达到。由于低速运行时燃料的不完全汽化或高速运行时对燃料的额外要求,实际操作中空气/燃料比通常比较浓。图表6表现了任何特定油门开度情况下实际的空气/燃料比。
化油器调整
一旦了解基本原理,化油器故障检修就是简单的事了。第一步是要找出引擎在何处运行欠佳。
7展现了通道以及每个部件在何处具有最大影响。必须牢记化油器工作状况是由油门位置而不是引擎转速决定的。如果引擎在低转速有问题(怠速到1/4油门开度),节流阀或者柱塞可能有故障了。如果引擎在1/4到3/4油门开度之间有问题,那么油针和主喷嘴(很有可能是油针)可能是故障所在。如果引擎在3/4油门开度到油门全开之间运行有问题,主量孔很可能出故障了。
当调整化油器时,在油门把手座上粘一片胶带。把另一片胶带粘在油门把手上,从一片胶带到另一片之间划一条直线(当油门处于怠速状态时)。当这两条线对齐的时候,引擎将是怠速运行。现在完全打开油门,并从油门把手上的线段开始划出另一条直线。在这一步,油门把手座上应该有两条线,在油门把手上有一条。现在找出油门把手座上的两条线段之间的中点。做一个标志,而且当油门处于半开时,这将会展现。再次向上分割间隔直到怠速,1/4,1/2,3/4,以及油门全开位置都被确定。这些线将被用来在调整时快速找出准确的油门开度。
清理空气过滤器而暖车
当摩托车怠速的时候,怠速通道可以被调整然後试运行。如果引擎运行不佳,仅仅能维持怠速,怠速量孔螺丝可以被旋入或旋出来改变空气燃料混合比。如果调整螺丝是在化油器的后面(像大多数越野车那样),旋出它将会使混合气变稀,旋入它将会使混合气变浓。如果调整螺丝是在化油器的前面(像大多数街车那样),情况则相反。如果螺丝在一圈至二圈半之间旋转没有任何影响,怠速量孔将必须换成更大或更小的。当调整怠速螺丝的时候,每次转1/4圈并在调整之间试运行摩托车。调整怠速螺丝直到摩托车从怠速到运行不感到迟滞。
在怠速量孔调整完毕后,换档加速直到油门处于半开位置。(向上的缓坡是最佳场所)在油门半开状态运行几分钟后,快速抓离合器并熄火。(不允许引擎怠速或在不分离离合器的情况下滑行)。取下火花塞并查看它的颜色。它应该是一种浅棕色。(关于火花塞的更多信息,请访问 http://wwwmotocrosscom/motoprof/moto/mcycle/plug2/plug2htm)。如果它发白,降低油针上的卡箍使空气/燃料混合物变浓。如果它是深褐色或黑色的,升高油针上的卡箍使空气/燃料混合物变稀。
一旦油针设置完毕,换档加速直到油门处于全开位置。快速抓离合器并熄火。(不允许引擎怠速或在不分离离合器的情况下滑行)。查看火花塞的颜色。如果它发白,说明空气/燃料混合物过稀,必须安装一个比较大的主量孔。如果它是黑色或深褐色,说明空气/燃料混合物过浓,必须安装一个比较小的主量孔。当更换量孔时,每次变更一个规格,每个更换后都要试运行,并在每次运行之後查看火花塞颜色。忽略照此操作会导致引擎失灵。
要真正完全调整好化油器要做的事情还有很多,但是以上步骤将使你真正接近(调整好化油器)并将会改善引擎性能。对于大多数赛车手,这些简单步骤都是必需的。如果你的名字是ricky,ezra,或kevin,而且你要去参加semi赛事,你的机械师将会知道该做什么。
高度,湿度和气温
即便调整完毕并且摩托车运行良好,还有许多因数会改变引擎的性能。高度,气温和湿度是影响引擎运行状况的重要因数。当空气比较寒冷时空气密度增加。这意味着当空气很冷的时候,在相同的空间中有较多的氧分子。当温度降低的时候,引擎将会运行于较稀的(混合气状态)(因为所有那些额外的空气分子),必须增加更多燃料以补偿。当气温比较热时,引擎将会运行于较浓的(混合气状态)(因为比较少的空气分子),对燃料的需求将会减少。当温度到达90华氏的时候,一个在华氏32度调整完毕的引擎可能运行不佳。
由于当海拔高度增加时空气分子减少,海拔高度将会影响发动机的调整。由于比较少的空气进入化油器。一辆在海平面高度运行良好的摩托车到了海拔10,000英尺高度时将会运行于混合气较浓的状态。
湿度是空气中水分含量的多少。当湿度增大,混合气将会比较浓。在早晨干爽空气中运行良好的摩托车在接下来的白天随着空气湿度的增加会运行于混合气较浓的状态。
修正因数有时被用来在温度和高度发生变化时找出正确的化油器设定。在8中的图表,展示了来自川崎的一个典型的修正因数图。为了使用这张图表,调整化油器并记录下节流阀和主量孔规格。测定正确气温并沿着图表向右直至找到正确的海拔高度。从这个点垂直向下直到找到正确的修正因数。以8为例,气温是华氏90度,海拔高度是3200英尺。修正因数将会是092。为了找到修正的主量孔和怠速量孔,将修正因数和每个喷嘴规格相乘。主量孔规格350被乘以092,新的主量孔规格会是322。怠速量孔规格40被乘以092,怠速量孔尺度会是368。
修正因数也能用来为主喷嘴,油针和空气螺丝找到正确设定。使用来自8的图表并确定修正因数。然后在使用9中的表格决定该如何调整主喷嘴,油针和空气螺丝。
现在你掌握它了。化油器理论。带来这段课程学来的知识,前去调整你的摩托车吧。知识就是力量。力量是任何事情。
水波纹效果:
1标准正余弦水波纹;
2非标准圆形液柱水波纹;
虽说都是水波纹,但两者在实现上差异是比较大的,一个通过正余弦函数模拟水波纹效果,另外一个会运用到图像的混合模式(PorterDuffXfermode);
先看效果:
自定义View根据实际情况可以选择继承自View、TextView、ImageView或其他
这次的实现我们都选择继承view,在实现的过程中我们需要关注如下几个方法:
1onMeasure():最先回调,用于控件的测量;
2onSizeChanged():在onMeasure后面回调,可以拿到view的宽高等数据,在横竖屏切换时也会回调;
3onDraw():真正的绘制部分,绘制的代码都写到这里面;
既然如此,我们先复写这三个方法,然后来实现如上两个效果;
一:标准正余弦水波纹
这种水波纹可以用具体函数模拟出具体的轨迹,所以思路基本如下:
1确定水波函数方程
2根据函数方程得出每一个波纹上点的坐标;
3将水波进行平移,即将水波上的点不断的移动;
4不断的重新绘制,生成动态水波纹;
有了上面的思路,我们一步一步进行实现:
正余弦函数方程为:
y = Asin(wx+b)+h ,这个公式里:w影响周期,A影响振幅,h影响y位置,b为初相;
根据上面的方程选取自己觉得中意的波纹效果,确定对应参数的取值;
然后根据确定好的方程得出所有的方程上y的数值,并将所有y值保存在数组里:
// 将周期定为view总宽度
mCycleFactorW = (float) (2 MathPI / mTotalWidth);
// 根据view总宽度得出所有对应的y值
for (int i = 0; i < mTotalWidth; i++) {
mYPositions[i] = (float) (STRETCH_FACTOR_A Mathsin(mCycleFactorW i) + OFFSET_Y);
}
根据得出的所有y值,则可以在onDraw中通过如下代码绘制两条静态波纹:
for (int i = 0; i < mTotalWidth; i++) {
// 减400只是为了控制波纹绘制的y的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果
// 绘制第一条水波纹
canvasdrawLine(i, mTotalHeight - mResetOneYPositions[i] - 400, i,
mTotalHeight,
mWavePaint);
// 绘制第二条水波纹
canvasdrawLine(i, mTotalHeight - mResetTwoYPositions[i] - 400, i,
mTotalHeight,
mWavePaint);
}
这种方式类似于数学里面的细分法,一条波纹,如果横向以一个像素点为单位进行细分,则形成view总宽度条直线,并且每条直线的起点和终点我们都能知道,在此基础上我们只需要循环绘制出所有细分出来的直线(直线都是纵向的),则形成了一条静态的水波纹;
接下来我们让水波纹动起来,之前用了一个数组保存了所有的y值点,有两条水波纹,再利用两个同样大小的数组来保存两条波纹的y值数据,并不断的去改变这两个数组中的数据:
private void resetPositonY() {
// mXOneOffset代表当前第一条水波纹要移动的距离
int yOneInterval = mYPositionslength - mXOneOffset;
// 使用Systemarraycopy方式重新填充第一条波纹的数据
Systemarraycopy(mYPositions, mXOneOffset, mResetOneYPositions, 0, yOneInterval);
Systemarraycopy(mYPositions, 0, mResetOneYPositions, yOneInterval, mXOneOffset);
int yTwoInterval = mYPositionslength - mXTwoOffset;
Systemarraycopy(mYPositions, mXTwoOffset, mResetTwoYPositions, 0,
yTwoInterval);
Systemarraycopy(mYPositions, 0, mResetTwoYPositions, yTwoInterval, mXTwoOffset);
}
如此下来只要不断的改变这两个数组的数据,然后不断刷新,即可生成动态水波纹了;
刷新可以调用invalidate()或postInvalidate(),区别在于后者可以在子线程中更新UI
整体代码如下:
package comcsdncsdnblog2ui;
import comcsdncsdnblog2utilsUiUtils;
import androidcontentContext;
import androidgraphicsCanvas;
import androidgraphicsDrawFilter;
import androidgraphicsPaint;
import androidgraphicsPaintStyle;
import androidgraphicsPaintFlagsDrawFilter;
import androidutilAttributeSet;
import androidviewView;
public class DynamicWave extends View {
// 波纹颜色
private static final int WAVE_PAINT_COLOR = 0x880000aa;
// y = Asin(wx+b)+h
private static final float STRETCH_FACTOR_A = 20;
private static final int OFFSET_Y = 0;
// 第一条水波移动速度
private static final int TRANSLATE_X_SPEED_ONE = 7;
// 第二条水波移动速度
private static final int TRANSLATE_X_SPEED_TWO = 5;
private float mCycleFactorW;
private int mTotalWidth, mTotalHeight;
private float[] mYPositions;
private float[] mResetOneYPositions;
private float[] mResetTwoYPositions;
private int mXOffsetSpeedOne;
private int mXOffsetSpeedTwo;
private int mXOneOffset;
private int mXTwoOffset;
private Paint mWavePaint;
private DrawFilter mDrawFilter;
public DynamicWave(Context context, AttributeSet attrs) {
super(context, attrs);
// 将dp转化为px,用于控制不同分辨率上移动速度基本一致
mXOffsetSpeedOne = UiUtilsdipToPx(context, TRANSLATE_X_SPEED_ONE);
mXOffsetSpeedTwo = UiUtilsdipToPx(context, TRANSLATE_X_SPEED_TWO);
// 初始绘制波纹的画笔
mWavePaint = new Paint();
// 去除画笔锯齿
mWavePaintsetAntiAlias(true);
// 设置风格为实线
mWavePaintsetStyle(StyleFILL);
// 设置画笔颜色
mWavePaintsetColor(WAVE_PAINT_COLOR);
mDrawFilter = new PaintFlagsDrawFilter(0, PaintANTI_ALIAS_FLAG | PaintFILTER_BITMAP_FLAG);
}
@Override
protected void onDraw(Canvas canvas) {
superonDraw(canvas);
// 从canvas层面去除绘制时锯齿
canvassetDrawFilter(mDrawFilter);
resetPositonY();
for (int i = 0; i < mTotalWidth; i++) {
// 减400只是为了控制波纹绘制的y的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果
// 绘制第一条水波纹
canvasdrawLine(i, mTotalHeight - mResetOneYPositions[i] - 400, i,
mTotalHeight,
mWavePaint);
// 绘制第二条水波纹
canvasdrawLine(i, mTotalHeight - mResetTwoYPositions[i] - 400, i,
mTotalHeight,
mWavePaint);
}
// 改变两条波纹的移动点
mXOneOffset += mXOffsetSpeedOne;
mXTwoOffset += mXOffsetSpeedTwo;
// 如果已经移动到结尾处,则重头记录
if (mXOneOffset >= mTotalWidth) {
mXOneOffset = 0;
}
if (mXTwoOffset > mTotalWidth) {
mXTwoOffset = 0;
}
// 引发view重绘,一般可以考虑延迟20-30ms重绘,空出时间片
postInvalidate();
}
private void resetPositonY() {
// mXOneOffset代表当前第一条水波纹要移动的距离
int yOneInterval = mYPositionslength - mXOneOffset;
// 使用Systemarraycopy方式重新填充第一条波纹的数据
Systemarraycopy(mYPositions, mXOneOffset, mResetOneYPositions, 0, yOneInterval);
Systemarraycopy(mYPositions, 0, mResetOneYPositions, yOneInterval, mXOneOffset);
int yTwoInterval = mYPositionslength - mXTwoOffset;
Systemarraycopy(mYPositions, mXTwoOffset, mResetTwoYPositions, 0,
yTwoInterval);
Systemarraycopy(mYPositions, 0, mResetTwoYPositions, yTwoInterval, mXTwoOffset);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
superonSizeChanged(w, h, oldw, oldh);
// 记录下view的宽高
mTotalWidth = w;
mTotalHeight = h;
// 用于保存原始波纹的y值
mYPositions = new float[mTotalWidth];
// 用于保存波纹一的y值
mResetOneYPositions = new float[mTotalWidth];
// 用于保存波纹二的y值
mResetTwoYPositions = new float[mTotalWidth];
// 将周期定为view总宽度
mCycleFactorW = (float) (2 MathPI / mTotalWidth);
// 根据view总宽度得出所有对应的y值
for (int i = 0; i < mTotalWidth; i++) {
mYPositions[i] = (float) (STRETCH_FACTOR_A Mathsin(mCycleFactorW i) + OFFSET_Y);
}
}
}
二:非标准圆形液柱水波纹
前面的波形使用函数模拟,这个我们换种方式,采用图进行实现,先用PS整张不像波纹的波纹图;
为了衔接紧密,首尾都比较平,并高度一致;
思路:
1使用一个圆形图作为遮罩过滤波形图;
2平移波纹图,即不断改变绘制的波纹图的区域,即srcRect;
3当一个周期绘制完,则从波纹图的最前面重新计算;
全部代码如下
// 初始化bitmap
private void initBitmap() {
mSrcBitmap = ((BitmapDrawable) getResourceswwwyingtaowcomzhidaogetDrawable(Rdrawablewave_2000))
getBitmap();
mMaskBitmap = ((BitmapDrawable) getResources()getDrawable(
Rdrawablecircle_500))
getBitmap();
}
// 初始化画笔paint
private void initPaint() {
mBitmapPaint = new Paint();
// 防抖动
mBitmapPaintsetDither(true);
// 开启图像过滤
mBitmapPaintsetFilterBitmap(true);
mPicPaint = new Paint(PaintANTI_ALIAS_FLAG);
mPicPaintsetDither(true);
mPicPaintsetColor(ColorRED);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
superonSizeChanged(w, h, oldw, oldh);
mTotalWidth = w;
mTotalHeight = h;
mCenterX = mTotalWidth / 2;
mCenterY = mTotalHeight / 2;
mSrcRect = new Rect();
mDestRect = new Rect(0, 0, mTotalWidth, mTotalHeight);
int maskWidth = mMaskBitmapgetWidth();
int maskHeight = mMaskBitmapgetHeight();
mMaskSrcRect = new Rect(0, 0, maskWidth, maskHeight);
mMaskDestRect = new Rect(0, 0, mTotalWidth, mTotalHeight);
}
}
欢迎分享,转载请注明来源:品搜搜测评网