水波纹效果:
1.标准正余弦水波纹;
2.非标准圆形液柱水波纹;
虽说都是水波纹,但两者在实现上差异是比较大的,一个通过正余弦函数模拟水波纹效果,另外一个会运用到图像的混合模式(PorterDuffXfermode);
先看效果:
自定义View根据实际情况可以选择继承自View、TextView、ImageView或其他
这次的实现我们都选择继承view,在实现的过程中我们需要关注如下几个方法:
1.onMeasure():最先回调,用于控件的测量;
2.onSizeChanged():在onMeasure后面回调,可以拿到view的宽高等数据,在横竖屏切换时也会回调;
3.onDraw():真正的绘制部分,绘制的代码都写到这里面;
既然如此,我们先复写这三个方法,然后来实现如上两个效果;
一:标准正余弦水波纹
这种水波纹可以用具体函数模拟出具体的轨迹,所以思路基本如下:
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个实例对象。