先看效果:
一,效果有两个,一个是波纹运动,另外一个就是头像运动(换成小船的图片更有趣哦)
二,实现步骤
1,使用贝塞尔曲线,确定path的路径。
2,绘制path路径,并且开启动画,使向右移动,达到水波纹效果。
3,确定头像的位置
4,绘制头像。
1,绘制波浪线,如图
2,填充区域,如图
3,Region和path相交,得到一个矩形区域
4,当这个矩形区域的左边和右边无限接近时,就可以把它看做一条直线,然后就可以得到中间线和path的相交点,这样就可以确定头像的位置了。
核心代码:
public WaveView(Context context, AttributeSet attrs) { super(context, attrs); //初始化自定义属性 initAttrs(context, attrs); init(); }
private void init() { paint = new Paint(); paint.setColor(getResources().getColor(R.color.colorPrimary)); paint.setStyle(Paint.Style.FILL_AND_STROKE); //填充 path = new Path(); } /** * 初始化自定义属性 * @param context * @param attrs */ private void initAttrs(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WaveView); waveView_boatBitmap = a.getResourceId(R.styleable.WaveView_boatBitmap, 0); rise = a.getBoolean(R.styleable.WaveView_rise, false); waveLength = (int) a.getDimension(R.styleable.WaveView_waveLength, 400); originY = (int) a.getDimension(R.styleable.WaveView_originY, 500); waveHeight = (int) a.getDimension(R.styleable.WaveView_waveHeight, 200); duration = (int) a.getDimension(R.styleable.WaveView_duration,2000); a.recycle(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; if(waveView_boatBitmap > 0){ mBitmap = BitmapFactory.decodeResource(getResources(),waveView_boatBitmap,options); mBitmap = getCircleBitmap(mBitmap); }else{ mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher,options); } }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //画水波纹曲线 //定义曲线path setPathData(); canvas.drawPath(path, paint); //绘制头像 Rect bounds = region.getBounds(); if(bounds.top > 0 || bounds.right > 0){ if(bounds.top < originY){ canvas.drawBitmap(mBitmap,bounds.right-mBitmap.getWidth()/2,bounds.top-mBitmap.getHeight(),paint); }else{ canvas.drawBitmap(mBitmap,bounds.right-mBitmap.getWidth()/2,bounds.bottom-mBitmap.getHeight(),paint); } }else{ float x = width/2 - mBitmap.getWidth()/2; canvas.drawBitmap(mBitmap,x,originY-mBitmap.getHeight(),paint); } } /** * 绘制曲线路径 */ private void setPathData() { //贝塞尔曲线 path.reset();; int halfWaveLength = waveLength / 2; //dx,使view不断右移,达到动起来效果 path.moveTo(-waveLength+dx,originY); //需要多画一个波长,万一只剩一点点,否则就空白了一些 for (int i = -waveLength; i < width+waveLength; i+= waveLength) { //画一个完整的波长,拆分成波峰和波谷 // //rQuadTo 相对位置的,相对于中间的基准线 path.rQuadTo(halfWaveLength/2, -waveHeight,halfWaveLength,0); path.rQuadTo(halfWaveLength/2, waveHeight,halfWaveLength,0); } //确定中间图片的位置 //曲线和中间线的相交 //区域范围 float x = width / 2; region = new Region(); //这样设置,矩形的左边和右边无限逼近,(也就差不多是一根直线了) Region clip = new Region((int)(x-0.1),0,(int)x,height); //用一个矩形区域去切割一个path路径,得到一个矩形区域 region.setPath(path,clip); //补充封闭的线 path.lineTo(width,height); path.lineTo(0,height); path.close(); //最后的关闭,会自动连接起来 } /** * 开启动画 */ public void startAnimation(){ animator = ValueAnimator.ofFloat(0,1); //不断的执行 animator.setRepeatCount(ValueAnimator.INFINITE); //使动画不卡顿,不用这个,会动一下,然后卡一下 animator.setInterpolator(new LinearInterpolator()); animator.setDuration(duration); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float fraction = (float) valueAnimator.getAnimatedValue(); //0-1 dx = (int) (waveLength * fraction); postInvalidate(); //然后重新绘制,调用ondraw,使循环运动。 } }); animator.start(); }
/** * 得到圆形的图片 * @param bitmap * @return */ public Bitmap getCircleBitmap(Bitmap bitmap){ try { Bitmap circleBitmap = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(circleBitmap); final Paint paint = new Paint(); final Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight()); final RectF rectF = new RectF(new Rect(0,0,bitmap.getWidth(),bitmap.getHeight())); float roundPx = 0.0f; //以较短的为准 if(bitmap.getWidth() > bitmap.getHeight()){ roundPx = bitmap.getHeight() / 2.0f; }else{ roundPx = bitmap.getWidth() / 2.0f; } paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(Color.WHITE); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); //图片和圆形相交的部分,取图片上相交的 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); final Rect src = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight()); canvas.drawBitmap(bitmap,src,rect,paint); return circleBitmap; }catch (Exception e){ return bitmap; } }
源码下载:http://download.csdn.net/download/shenbin1/10027671