1、效果图:主要模仿Fuubo的欢迎界面,一个三层扩散的水波纹.
2、实现思路:
1、在布局主要用帧布局,让三个水波纹的View重叠
2、设置三个水波纹的View扩散的延迟时间
3、可设置三个水波纹的View的坐标,
可设置是否开始(因为我们有时要Activity中先设置好波纹的坐标,不能让波纹先出现),
可设置是否为第一次(第一次要进行初始化主要为了设置延迟,不然每次都会有延迟,不同延迟时间的SpreadView相差的时间越来越多)。
3、实现:
根据思路所以接下来要做的一个自定义VIEW就是去绘制一个可扩散的,可设置扩散延迟的实心圆。
1、 先设置自定义View属性(attr文件中):
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="SpreadView">
- <attr name="xDown" format="integer" />
- <attr name="yDown" format="integer" />
- <attr name="start" format="boolean" />
- <attr name="delay" format="integer" />
- <attr name="first" format="boolean" />
- </declare-styleable>
- </resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SpreadView">
<attr name="xDown" format="integer" />
<attr name="yDown" format="integer" />
<attr name="start" format="boolean" />
<attr name="delay" format="integer" />
<attr name="first" format="boolean" />
</declare-styleable>
</resources>
2、 然后新建一个继承View的SpreadView类:
- public class SpreadView extends View {
- //建立一个波纹的集合
- private List<Wave> waveList;
- //波纹的x,y坐标
- private int x = 0 ;
- private int y = 0 ;
- //波纹是否在运行,是否为第一次
- private boolean start ,first ;
- //波纹开始的延迟时间
- private int delay ;
- public void setStart(boolean start) {
- this.start = start;
- }
- public void setFirst(boolean first) {
- this.first = first;
- }
- public void setX(int x) {
- this.x = x;
- }
- public void setY(int y) {
- this.y = y;
- }
- public void setDelay(int delay) {
- this.delay = delay;
- }
- //波纹设置的最大透明度
- private static final int MAX_ALPHA = 255;
- public SpreadView(Context context, AttributeSet attrs) {
- super(context, attrs);
- //获取属性信息和设置默认值
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.SpreadView);
- x = a.getInt(R.styleable.SpreadView_xDown,0);
- y = a.getInt(R.styleable.SpreadView_yDown,0);
- start = a.getBoolean(R.styleable.SpreadView_start,false);
- delay = a.getInt(R.styleable.SpreadView_delay,0);
- first = a.getBoolean(R.styleable.SpreadView_first,true);
- //波纹集合的实例化
- waveList = Collections.synchronizedList(new ArrayList<Wave>());
- //记得回收属性容器
- a.recycle();
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- if(waveList.size()==0&&(!first)) //波纹集合大小为0时,初始化
- init(); //非第一次初始化
- else if(waveList.size()==0&&first)
- initFirst(); //第一次初始化
- //绘制圆
- Wave wave = waveList.get(0);
- if(wave!=null)
- canvas.drawCircle(wave.xDown, wave.yDown, wave.radius, wave.paint);//用波纹的属性
- }
- private void initFirst() {
- if(this.start) { //如果属性值设为开始
- Wave wave = new Wave();
- wave.radius = 0;
- wave.alpha = MAX_ALPHA;
- wave.xDown = x;
- wave.yDown = y;
- wave.paint = initPaint(wave.alpha);
- waveList.add(wave);
- first = false; //设置第一次为false
- mHandler.sendEmptyMessageDelayed(0, delay);//带延迟异步任务
- }
- }
- //更新画笔
- private Paint initPaint(int alpha) {
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setAlpha(alpha);
- paint.setColor(Color.WHITE);
- return paint;
- }
- public final Handler.Callback mHandlerCallback = new Handler.Callback(){
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what){
- case 0:
- refreshState();
- invalidate();
- if (waveList != null &&waveList.size()>0) {
- mHandler.sendEmptyMessage(0); //不带延迟的异步
- }
- return true;
- default:
- return false;
- }
- }
- };
- private Handler mHandler = new Handler(mHandlerCallback);
- private void refreshState() {
- Wave w = waveList.get(0);
- if (w == null) {
- this.postInvalidate(); //如果没有波纹就重新绘制,重新运行onDraw()初始化
- } else {
- //波纹每次增加的半径大小,可自己修改,记得要转换为px。
- //(这里0.6单位为dp可以大概指出最大半径),如果不转换,那波纹的最大半径因手机的分辨率不同而不同
- w.radius += dip2px(getContext(),0.6f);
- //波纹每次减小的透明度
- w.alpha -= 1;
- //更新波纹的透明度
- w.paint.setAlpha(w.alpha);
- //当透明度小于0时,清理波纹列表,重新绘制初始化
- if (w.alpha < 0) {
- waveList.clear();
- this.postInvalidate();
- }
- }
- }
- public void init() {
- if(this.start) {
- Wave wave = new Wave();
- wave.radius = 0;
- wave.alpha = MAX_ALPHA;
- wave.xDown = x;
- wave.yDown = y;
- wave.paint = initPaint(wave.alpha);
- waveList.add(wave);
- mHandler.sendEmptyMessageDelayed(0, 1000);
- }
- }
- private class Wave {
- float radius;
- Paint paint;
- int xDown;
- int yDown;
- int alpha;
- }
- public static int dip2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
- }
public class SpreadView extends View {
//建立一个波纹的集合
private List<Wave> waveList;
//波纹的x,y坐标
private int x = 0 ;
private int y = 0 ;
//波纹是否在运行,是否为第一次
private boolean start ,first ;
//波纹开始的延迟时间
private int delay ;
public void setStart(boolean start) {
this.start = start;
}
public void setFirst(boolean first) {
this.first = first;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setDelay(int delay) {
this.delay = delay;
}
//波纹设置的最大透明度
private static final int MAX_ALPHA = 255;
public SpreadView(Context context, AttributeSet attrs) {
super(context, attrs);
//获取属性信息和设置默认值
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SpreadView);
x = a.getInt(R.styleable.SpreadView_xDown,0);
y = a.getInt(R.styleable.SpreadView_yDown,0);
start = a.getBoolean(R.styleable.SpreadView_start,false);
delay = a.getInt(R.styleable.SpreadView_delay,0);
first = a.getBoolean(R.styleable.SpreadView_first,true);
//波纹集合的实例化
waveList = Collections.synchronizedList(new ArrayList<Wave>());
//记得回收属性容器
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
if(waveList.size()==0&&(!first)) //波纹集合大小为0时,初始化
init(); //非第一次初始化
else if(waveList.size()==0&&first)
initFirst(); //第一次初始化
//绘制圆
Wave wave = waveList.get(0);
if(wave!=null)
canvas.drawCircle(wave.xDown, wave.yDown, wave.radius, wave.paint);//用波纹的属性
}
private void initFirst() {
if(this.start) { //如果属性值设为开始
Wave wave = new Wave();
wave.radius = 0;
wave.alpha = MAX_ALPHA;
wave.xDown = x;
wave.yDown = y;
wave.paint = initPaint(wave.alpha);
waveList.add(wave);
first = false; //设置第一次为false
mHandler.sendEmptyMessageDelayed(0, delay);//带延迟异步任务
}
}
//更新画笔
private Paint initPaint(int alpha) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setAlpha(alpha);
paint.setColor(Color.WHITE);
return paint;
}
public final Handler.Callback mHandlerCallback = new Handler.Callback(){
@Override
public boolean handleMessage(Message msg) {
switch (msg.what){
case 0:
refreshState();
invalidate();
if (waveList != null &&waveList.size()>0) {
mHandler.sendEmptyMessage(0); //不带延迟的异步
}
return true;
default:
return false;
}
}
};
private Handler mHandler = new Handler(mHandlerCallback);
private void refreshState() {
Wave w = waveList.get(0);
if (w == null) {
this.postInvalidate(); //如果没有波纹就重新绘制,重新运行onDraw()初始化
} else {
//波纹每次增加的半径大小,可自己修改,记得要转换为px。
//(这里0.6单位为dp可以大概指出最大半径),如果不转换,那波纹的最大半径因手机的分辨率不同而不同
w.radius += dip2px(getContext(),0.6f);
//波纹每次减小的透明度
w.alpha -= 1;
//更新波纹的透明度
w.paint.setAlpha(w.alpha);
//当透明度小于0时,清理波纹列表,重新绘制初始化
if (w.alpha < 0) {
waveList.clear();
this.postInvalidate();
}
}
}
public void init() {
if(this.start) {
Wave wave = new Wave();
wave.radius = 0;
wave.alpha = MAX_ALPHA;
wave.xDown = x;
wave.yDown = y;
wave.paint = initPaint(wave.alpha);
waveList.add(wave);
mHandler.sendEmptyMessageDelayed(0, 1000);
}
}
private class Wave {
float radius;
Paint paint;
int xDown;
int yDown;
int alpha;
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
3、 先设置xml布局:
注意每个SpreadView的延迟时间和ImageView的属性
4、接下来我们就要根据上面的布局在Activity手动计算波纹位置了:我们要把波纹的中心设在图片的中心(可看开始的效果图)
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/main"
- >
- <com.scb.administrator.a.SpreadView
- android:id="@+id/sv"
- app:xDown="0"
- app:yDown="0"
- app:start="false"
- app:first="true"
- app:delay="0"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <com.scb.administrator.a.SpreadView
- android:id="@+id/sv1"
- app:xDown="0"
- app:yDown="0"
- app:start="false"
- app:first="true"
- app:delay="1900"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <com.scb.administrator.a.SpreadView
- android:id="@+id/sv2"
- app:xDown="0"
- app:yDown="0"
- app:first="true"
- app:start="false"
- app:delay="3800"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#00000000"
- android:id="@+id/re_create2"
- >
- <TextView
- android:gravity="center"
- android:textSize="19sp"
- android:layout_margin="80dp"
- android:textStyle="italic"
- android:textColor="@color/white"
- android:text="H\nU\nS\nT\nO\nO"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <ImageView
- android:id="@+id/go"
- android:background="#00000000"
- android:src="@drawable/fap_login"
- android:layout_margin="40dp"
- android:scaleType="centerCrop"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_width="54dp"
- android:layout_height="54dp" />
- </RelativeLayout>
- </FrameLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main"
>
<com.scb.administrator.a.SpreadView
android:id="@+id/sv"
app:xDown="0"
app:yDown="0"
app:start="false"
app:first="true"
app:delay="0"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.scb.administrator.a.SpreadView
android:id="@+id/sv1"
app:xDown="0"
app:yDown="0"
app:start="false"
app:first="true"
app:delay="1900"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.scb.administrator.a.SpreadView
android:id="@+id/sv2"
app:xDown="0"
app:yDown="0"
app:first="true"
app:start="false"
app:delay="3800"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
android:id="@+id/re_create2"
>
<TextView
android:gravity="center"
android:textSize="19sp"
android:layout_margin="80dp"
android:textStyle="italic"
android:textColor="@color/white"
android:text="H\nU\nS\nT\nO\nO"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/go"
android:background="#00000000"
android:src="@drawable/fap_login"
android:layout_margin="40dp"
android:scaleType="centerCrop"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_width="54dp"
android:layout_height="54dp" />
</RelativeLayout>
</FrameLayout>
4、接下来我们就要根据上面的布局在Activity手动计算波纹位置了:我们要把波纹的中心设在图片的中心(可看开始的效果图)