android 水动画,Android自定义View实现水波纹引导动画

一、实现效果图

15059063031.gif?2017023165049

关于贝塞尔曲线

15059063042.jpg?201702316518

二、实现代码

1.自定义view

package com.czhappy.showintroduce.view;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.util.AttributeSet;

import android.view.View;

import android.widget.RelativeLayout;

/**

* Description: 水波纹动画引导view

* User: chenzheng

* Date: 2017/1/14 0014

* Time: 18:01

*/

public class RippleIntroView extends RelativeLayout implements Runnable {

private int mMaxRadius = 70;

private int mInterval = 20;

private int count = 0;

private Bitmap mCacheBitmap;

private Paint mRipplePaint;

private Paint mCirclePaint;

private Path mArcPath;

public RippleIntroView(Context context) {

this(context,null);

}

public RippleIntroView(Context context,AttributeSet attrs) {

this(context,attrs,0);

}

public RippleIntroView(Context context,AttributeSet attrs,int defStyleAttr) {

super(context,defStyleAttr);

init();

}

private void init() {

mRipplePaint = new Paint();

mRipplePaint.setAntiAlias(true);

mRipplePaint.setStyle(Paint.Style.STROKE);

mRipplePaint.setColor(Color.WHITE);

mRipplePaint.setStrokeWidth(2.f);

mCirclePaint = new Paint();

mCirclePaint.setAntiAlias(true);

mCirclePaint.setStyle(Paint.Style.FILL);

mCirclePaint.setColor(Color.WHITE);

mArcPath = new Path();

}

/**

* view大小变化时系统调用

* @param w

* @param h

* @param oldw

* @param oldh

*/

@Override

protected void onSizeChanged(int w,int h,int oldw,int oldh) {

super.onSizeChanged(w,h,oldw,oldh);

if (mCacheBitmap != null) {

mCacheBitmap.recycle();

mCacheBitmap = null;

}

}

@Override

protected void onDraw(Canvas canvas) {

//获取加号图片view

View mPlusChild = getChildAt(0);

//获取提示图片view

View mRefsChild = getChildAt(1);

if (mPlusChild == null || mRefsChild == null) return;

//获取加号图片大小

final int pw = mPlusChild.getWidth();

final int ph = mPlusChild.getHeight();

//获取提示图片大小

final int fw = mRefsChild.getWidth();

final int fh = mRefsChild.getHeight();

if (pw == 0 || ph == 0) return;

//加号图片中心点坐标

final float px = mPlusChild.getX() + pw / 2;

final float py = mPlusChild.getY() + ph / 2;

//提示图片左上角坐标

final float fx = mRefsChild.getX();

final float fy = mRefsChild.getY();

final int rw = pw / 2;

final int rh = ph / 2;

if (mCacheBitmap == null) {

mCacheBitmap = Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);

Canvas cv = new Canvas(mCacheBitmap);

super.onDraw(cv);

//清空所有已经画过的path至原始状态

mArcPath.reset();

//起始轮廓点移至x,y坐标点,即加号图片正下方再往下20位置

mArcPath.moveTo(px,py + rh + mInterval);

//设置二次贝塞尔,实现平滑曲线,前两个参数为操作点坐标,后两个参数为结束点坐标

mArcPath.quadTo(px,fy - mInterval,fx + fw * 0.618f,fy - mInterval);

//0~255,数值越小越透明

mRipplePaint.setAlpha(255);

cv.drawPath(mArcPath,mRipplePaint);

//绘制半径为6的实心圆点

cv.drawCircle(px,py + rh + mInterval,6,mCirclePaint);

}

//绘制背景图片

canvas.drawBitmap(mCacheBitmap,mCirclePaint);

//保存画布当前的状态

int save = canvas.save();

for (int step = count; step <= mMaxRadius; step += mInterval) {

//step越大越靠外就越透明

mRipplePaint.setAlpha(255 * (mMaxRadius - step) / mMaxRadius);

canvas.drawCircle(px,py,(float) (rw + step),mRipplePaint);

}

//恢复Canvas的状态

canvas.restoreToCount(save);

//延迟80毫秒后开始运行

postDelayed(this,80);

}

@Override

public void run() {

//把run对象的引用从队列里拿出来,这样,他就不会执行了,但 run 没有销毁

removeCallbacks(this);

count += 2;

count %= mInterval;

invalidate();//重绘

}

/**

* 销毁view时调用,收尾工作

*/

@Override

protected void onDetachedFromWindow() {

super.onDetachedFromWindow();

if (mCacheBitmap != null) {

mCacheBitmap.recycle();

mCacheBitmap = null;

}

}

}

2.MainActivity.java

package com.czhappy.showintroduce.activity;

import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import android.view.View;

import android.view.ViewGroup;

import com.czhappy.showintroduce.R;

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

View view = findViewById(R.id.layout_ripple);

view.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

((ViewGroup) v.getParent()).removeView(v);

}

});

}

}

3.activity_main.xml

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Hello World!" />

android:id="@+id/layout_ripple"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:clickable="true"

android:fitsSystemWindows="true"

android:background="#AA000000">

android:id="@+id/iv_plus"

android:layout_marginTop="36dp"

android:src="@mipmap/ic_add"

android:layout_alignParentRight="true"

android:layout_marginRight="6dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

android:src="@mipmap/tips_subscribe"

android:id="@+id/tv_title"

android:layout_below="@id/iv_plus"

android:layout_marginTop="50dp"

android:layout_alignParentRight="true"

android:layout_marginRight="40dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content"/>

三、源码下载

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

小编个人微信号 jb51ccc

喜欢与人分享编程技术与工作经验,欢迎加入编程之家官方交流群!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值