android自定义组件手机加速球+水面波动效果.docx

上传人:b****5 文档编号:14822567 上传时间:2023-06-27 格式:DOCX 页数:19 大小:282.37KB
下载 相关 举报
android自定义组件手机加速球+水面波动效果.docx_第1页
第1页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第2页
第2页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第3页
第3页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第4页
第4页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第5页
第5页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第6页
第6页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第7页
第7页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第8页
第8页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第9页
第9页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第10页
第10页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第11页
第11页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第12页
第12页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第13页
第13页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第14页
第14页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第15页
第15页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第16页
第16页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第17页
第17页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第18页
第18页 / 共19页
android自定义组件手机加速球+水面波动效果.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

android自定义组件手机加速球+水面波动效果.docx

《android自定义组件手机加速球+水面波动效果.docx》由会员分享,可在线阅读,更多相关《android自定义组件手机加速球+水面波动效果.docx(19页珍藏版)》请在冰点文库上搜索。

android自定义组件手机加速球+水面波动效果.docx

android自定义组件手机加速球+水面波动效果

android自定义组件(手机加速球+水面波动效果)

自定义View确定一个正方形

publicclassWaterViewextendsView{

privateintlen;

publicWaterView(Contextcontext,@NullableAttributeSetattrs){

super(context,attrs);

}

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

intwidth=MeasureSpec.getSize(widthMeasureSpec);

intheight=MeasureSpec.getSize(heightMeasureSpec);

//以最小值为正方形的长

len=Math.min(width,height);

//设置测量高度和宽度(必须要调用,不然无效果)

setMeasuredDimension(len,len);

}

@Override

protectedvoidonDraw(Canvascanvas){

super.onDraw(canvas);

}

}

同样这里集成了View,并通过设置测量值,限定空间为正方形。

布局中使用:

xmlversion="1.0"encoding="utf-8"?

>

android:

layout_width="match_parent"

android:

layout_height="match_parent"

android:

id="@+id/ll_parent"

android:

orientation="vertical"

android:

background="@color/colorPrimary"

android:

padding="20dp"

tools:

context="com.example.huaweiview.MainActivity">

android:

layout_gravity="center"

android:

background="@color/colorAccent"

android:

layout_width="200dp"

android:

layout_height="300dp"/>

ok,我们设置的长度和宽度并不一样,但是他显示的是一个正方形,并且,根据上一篇博客的介绍,它是有自己的坐标系的,我们绘制的所有东西都在这个坐标系内,并且依靠它去确定位置。

回忆正余弦

大家通过查资料和联想心电图等可以知道,水波其实就是在绘制一条正弦或者余弦波,如果让这条波移动就是

这里我们使用正弦实现需要如下公式:

y=Asin(wx+b)+h,这个公式里:

w影响周期,A影响振幅,h影响y位置,b为初相;

画图就少不了要确定不同的点,通过这个公式,我们可以得到Y轴坐标点的值,那么X轴坐标点的值该如何得到呢?

通过观察图我们可以发现,这些点连起来就是一条曲线,也就是说每个点之间的距离是非常小的,是不是可以用,这些所有的点都在X轴上有值,刚好是i(i从0加到len的长度(View的长度也就是圆的直径))

比如图中的中间点的坐标(y=0,x=i=len/2)

当然Y值是通过公式得到的,既然有很多点,我们就需要用数组来保存这些点,水波效果最好是有两条效果会好些,所以需要个数组:

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

intwidth=MeasureSpec.getSize(widthMeasureSpec);

intheight=MeasureSpec.getSize(heightMeasureSpec);

//以最小值为正方形的长

len=Math.min(width,height);

//定义两个数组,保存Y值

firstWaterLine=newfloat[len];

secondWaterLine=newfloat[len];

//设置测量高度和宽度(必须要调用,不然无效果)

setMeasuredDimension(len,len);

}

这里定义了两个全局数组,用来保存Y轴值,个数和View长度相等(直径相等)

然后就是利用公式获取每个点的Y轴坐标值

@Override

protectedvoidonDraw(Canvascanvas){

//y=Asin(wx+b)+h,这个公式里:

w影响周期,A影响振幅,h影响y位置,b为初相;

//将周期定为view总宽度

floatmCycleFactorW=(float)(2*Math.PI/len);

//得到第一条波的y值

for(nti=0;i

firstWaterLine[i]=(float)(10*Math

.sin(mCycleFactorW*i));

}

//得到第二条波的y值(第二条波的初相偏左)

for(inti=0;i

secondWaterLine[i]=(float)(15*Math.sin(mCycleFactorW*i+10));

}

}

在onDraw()方法中分别得到了两个数组中Y轴的值,并且将他一个周期的长度定位len(和直径相等)每个值都对应着一个X轴的值,也就是说我们得到两个正弦波上的所有点的坐标值了。

并且第二天波偏左一点

而且还要增加一下他们的振幅,不然0-1之间的值太小,显示在屏幕上像一条直线。

上图是什么意思呢?

我们的水波效果是下面有填充色的,那么这些填充色其实就是波上的每个点,往View的底边画的一条一条的直线(数学中的细分法或者微积分吧)然后线就组成了面。

ok,划线需要知道起点坐标,和终点坐标,如图中的两个绿色的坐标点。

(i,y)到(i,len);接下来开始画直线

publicWaterView(Contextcontext,@NullableAttributeSetattrs){

super(ntext,attrs);

waterPaint=newPaint();

//抗锯齿

waterPaint.setAntiAlias(true);

waterPaint.setColor(Color.GREEN);

}

@Override

protectedvoidonDraw(Canvascanvas){

//y=Asin(wx+b)+h,这个公式里:

w影响周期,A影响振幅,h影响y位置,b为初相;

//将周期定为view总宽度

floatmCycleFactorW=(float)(2*Math.PI/len);

//得到第一条波的y值

for(inti=0;i

firstWaterLine[i]=(float)(10*Math

.sin(mCycleFactorW*i));

}

//得到第二条波的y值

for(inti=0;i

secondWaterLine[i]=(float)(15*Math.sin(mCycleFactorW*i+10));

}

//第一条波的所有直线

for(inti=0;i

canvas.drawLine(i,firstWaterLine[i],i,len,waterPaint);

}

//第二条波的所有直线

for(inti=0;i

canvas.drawLine(i,secondWaterLine[i],i,len,waterPaint);

}

}

构造方法中实例化出了一个画笔对象,颜色为绿色,抗锯齿。

在onDraw()方法中添加了两个画直线的方法,我们要对每个点都要绘制所以使用了循环。

哎呀,这不是咱们想看到的效果呀,这是因为坐标的原点依旧在View的左上角,振幅小,都往下方画直线就覆盖了整个View,接下来我们把坐标系往下放移动len/2的距离,再去绘制:

@Override

protectedvoidonDraw(Canvascanvas){

//y=Asin(wx+b)+h,这个公式里:

w影响周期,A影响振幅,h影响y位置,b为初相;

//将周期定为view总宽度

floatmCycleFactorW=(float)(2*Math.PI/len);

//得到第一条波的y值

for(inti=0;i

firstWaterLine[i]=(float)(10*Math

.sin(mCycleFactorW*i));

}

//得到第二条波的y值

for(inti=0;i

secondWaterLine[i]=(float)(15*Math.sin(mCycleFactorW*i+10));

}

//保存原来的内容

canvas.save();

canvas.translate(0,len/2);

//第一条波的所有直线

for(inti=0;i

canvas.drawLine(i,firstWaterLine[i],i,len,waterPaint);

}

//第二条波的所有直线

for(inti=0;i

canvas.drawLine(i,secondWaterLine[i],i,len,waterPaint);

}

//恢复到原来的状态(会自动结合绘制的内容)

canvas.restore();;

}

现在是我们想看到的样子了,但是还有一点,我们希望他是一个圆形的,这时候就需要另外一个功能,cavans的剪切功能

@Override

protectedvoidonDraw(Canvascanvas){

//y=Asin(wx+b)+h,这个公式里:

w影响周期,A影响振幅,h影响y位置,b为初相;

//将周期定为view总宽度

floatmCycleFactorW=(float)(2*Math.PI/len);

//得到第一条波的y值

for(inti=0;i

firstWaterLine[i]=(float)(10*Math

.sin(mCycleFactorW*i));

}

//得到第二条波的y值

for(inti=0;i

secondWaterLine[i]=(float)(15*Math.sin(mCycleFactorW*i+10));

}

//裁剪成圆形区域

Pathpath=newPath();

eset();

floatclipRadius=len/2;

//添加圆形路径

//Path.Direction.CCW逆时针

//Path.Direction.CW顺时针

path.addCircle(len/2,len/2,clipRadius,Path.Direction.CCW);

//(剪裁路径)裁剪成圆形区域

//(REPLACE用当前要剪切的区域代替画布中的内容的区域)

canvas.clipPath(path,android.graphics.Region.Op.REPLACE);

canvas.save();

canvas.translate(0,len/2);

//第一条波的所有直线

for(inti=0;i

canvas.drawLine(i,firstWaterLine[i],i,len,waterPaint);

}

//第二条波的所有直线

for(inti=0;i

canvas.drawLine(i,secondWaterLine[i],i,len,waterPaint);

}

canvas.restore();;

}

在布局中我去除了,控件的背景,效果如图所示,接下来就是去控制让他动起来了,水平方向移动也就是每次初相都不相同,开启时间任务,让它的初相值不断变化(从右往左移动就加上一个数)

@Override

protectedvoidonDraw(Canvascanvas){

//y=Asin(wx+b)+h,这个公式里:

w影响周期,A影响振幅,h影响y位置,b为初相;

//将周期定为view总宽度

floatmCycleFactorW=(float)(2*Math.PI/len);

//得到第一条波的y值

for(inti=0;i

//添加一个可变的初相值

firstWaterLine[i]=(float)(10*Math

.sin(mCycleFactorW*i+move));

}

//得到第二条波的y值

for(inti=0;i

//添加一个可变的初相值

secondWaterLine[i]=(float)(15*Math.sin(mCycleFactorW*i+move+10));

}

//裁剪成圆形区域

Pathpath=newPath();

path.reset();

floatclipRadius=len/2;

//添加圆形路径

//Path.Direction.CCW逆时针

//Path.Direction.CW顺时针

path.addCircle(len/2,len/2,clipRadius,Path.Direction.CCW);

//(剪裁路径)裁剪成圆形区域

//(REPLACE用当前要剪切的区域代替画布中的内容的区域)

canvas.clipPath(path,android.graphics.Region.Op.REPLACE);

canvas.save();

canvas.translate(0,len/2);

//第一条波的所有直线

for(inti=0;i

canvas.drawLine(i,firstWaterLine[i],i,len,waterPaint);

}

//第二条波的所有直线

for(inti=0;i

canvas.drawLine(i,secondWaterLine[i],i,len,waterPaint);

}

canvas.restore();;

}

在onDraw()的方法中,获取坐标Y值的时候,添加一条可变的全局变量,动态改变初相值。

开启时间任务:

publicvoidmoveWaterLine(){

finalTimertimer=newTimer();

timer.schedule(newTimerTask(){

@Override

publicvoidrun(){

//不断改变初相

move+=1;

//重新绘制(子线程中调用)

postInvalidate();

}

},500,200);

}

在时间任务中,这里没用去关闭时间任务,它会一直动,,动态去改变,并在构造方法中去调用

效果已经很不错了,如何让它去增加和减少呢,让它从下往上增加,只要不断去影响Y的值就好了,

如果坐标系不改变,绘制水波的时候还要判断是增加还是减少,为了方便计算,只需要将坐标系移动到底部就好了,为0的时候代表什么都没用,有的时候让Y值不断的减去一个值就实现了网上增加。

@Override

protectedvoidonDraw(Canvascanvas){

//y=Asin(wx+b)+h,这个公式里:

w影响周期,A影响振幅,h影响y位置,b为初相;

//将周期定为view总宽度

floatmCycleFactorW=(float)(2*Math.PI/len);

//得到第一条波的y值

for(inti=0;i

//添加一个可变的初相值

firstWaterLine[i]=(float)(10*Math

.sin(mCycleFactorW*i+move)-up);

}

//得到第二条波的y值

for(inti=0;i

//添加一个可变的初相值

secondWaterLine[i]=(float)(15*Math.sin(mCycleFactorW*i+move+10)-up);

}

//裁剪成圆形区域

Pathpath=newPath();

path.reset();

floatclipRadius=len/2;

//添加圆形路径

//Path.Direction.CCW逆时针

//Path.Direction.CW顺时针

path.addCircle(len/2,len/2,clipRadius,Path.Direction.CCW);

//(剪裁路径)裁剪成圆形区域

//(REPLACE用当前要剪切的区域代替画布中的内容的区域)

canvas.clipPath(path,android.graphics.Region.Op.REPLACE);

canvas.save();

canvas.translate(0,len);

//第一条波的所有直线

for(inti=0;i

canvas.drawLine(i,firstWaterLine[i],i,len,waterPaint);

}

//第二条波的所有直线

for(inti=0;i

canvas.drawLine(i,secondWaterLine[i],i,len,waterPaint);

}

canvas.restore();

;

}

在onDraw()方法中将坐标系移动到底部,并且声明一个全局变量up来动态改变Y值,因为是从下往上运动,所以是减去,开启时间任务:

//如果在运行,就不会执行下次动画

privatebooleanisRunning;

//判断是上升还是下降

publicintstate=1;

publicvoidchange(finalinttrueAngle){

if(isRunning){

return;

}

finalTimertimer=newTimer();

timer.schedule(newTimerTask(){

@Override

publicvoidrun(){

switch(state){

case1:

isRunning=true;

up-=10;

if(up<=0){

up=0;

state=2;

}

break;

case2:

up+=10;

if(up>=trueAngle){

up=trueAngle;

state=1;

isRunning=false;

timer.cancel();

}

break;

default:

break;

}

postInvalidate();

}

},500,30);

}

声明一个boolean值来判断是否在运动,如果在动,就不进行下次运动,声明一个state变量来判断是上还是下

up值动态增加或减小,再重复绘制

activity调用

publicclassMainActivityextendsAppCompatActivity{

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(vedInstanceState);

setContentView(R.layout.activity_main);

finalWaterViewwv=(WaterView)findViewById(R.id.wv);

wv.setOnClickListener(newView.OnClickListener(){

@Override

publicvoidonClick(Viewv){

wv.change(200);

}

});

}

}

设置点击事件,调用动的方法

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 企业管理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2