概述:
360安全卫士的那个刷新球(姑且叫它刷新球,因为真的不知道叫什么好,不是dota里的刷新球!!),里面像住了水一样,生动可爱,看似简单,写起来不太简单,本例程只是实现了它的部分功能而已,说实话,跟360的刷新球比起来差距还是很大,我这个长得有点挫。
本历程需要用到的知识包括:android的自定义View,自定义canvas、path、Bitmap、Handler
先结果演示:
Damo
public class MyPathView extends View {
private int width;
private int height;
private int progress;
private int maxProgress = 100;
private Path mPath;
private Paint mPaintCircle;
private Paint mPaintWave;
private Paint mPaintText;
private Bitmap mBitmapBubble;
private Canvas mCanvasBitmap;
private int size = 0;//水波动幅度
private int count;//水流动距离
private boolean isAdd = true;
private static final int START_WAVE = 0x21;
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
invalidate();
}
public int getMaxProgress() {
return maxProgress;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case START_WAVE:
count += 30;
if (count >= 180) {
count = 0;
}
if (isAdd) {
size += 7;
if (size > 41) {
isAdd = false;
}
} else {
size -= 7;
if (size <= -41) {
isAdd = true;
}
}
invalidate();
sendEmptyMessageDelayed(START_WAVE, 100);
break;
}
}
};
public MyPathView(Context context) {
super(context);
}
public MyPathView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaintCircle = new Paint();
mPaintCircle.setStyle(Paint.Style.FILL_AND_STROKE);
mPaintCircle.setColor(Color.argb(0X4f, 0x4d, 0x4d, 0xff));
mPaintText = new Paint();
mPaintText.setColor(Color.WHITE);
mPaintText.setTextSize(50);
mPaintText.setTextAlign(Paint.Align.CENTER);
mPaintWave = new Paint();
mPaintWave.setColor(Color.argb(0xaa, 0xff, 0x7c, 0x00));
mPaintWave.setStyle(Paint.Style.FILL);
//不显示非重叠部分,并且重叠部分显示自己
PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
mPaintWave.setXfermode(mode);
mPath = new Path();
handler.sendEmptyMessageDelayed(START_WAVE, 1000);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
mBitmapBubble = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvasBitmap = new Canvas(mBitmapBubble);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
//canvas.drawColor(Color.argb(0xaa, 0x88, 0x7e, 0x7f));//自定义颜色
mCanvasBitmap.drawCircle(width / 2, height / 2, 200, mPaintCircle);
mPath.reset();
//用path圈出一个矩形,把水波和球的包含进去
mPath.moveTo(width / 2 + 200, height / 2 + 200 - progress / maxProgress * 400);
mPath.lineTo(width / 2 + 200, height / 2 + 200);
mPath.lineTo(0, height / 2 + 200);
mPath.lineTo(0, height / 2 + 200 - progress / maxProgress * 400);
/*
画一条个模拟流动的波浪
*/
//当count增大时,重绘会显示向前流动效果,count的值不能大于width/2-200
mPath.lineTo(count, height / 2 + 200 -(float) progress / maxProgress * 400);
// mPath.moveTo(count,200);
//size的从大到小从小到大变化,重绘时会产生波浪起伏效果
for (int i = 0; i < 20; i++) {
/*
rQuadTo()方法每次都会自动移动到下一位置,参数依次为水平幅度,
垂直幅度,水平位移,处置位移
*/
mPath.rQuadTo(20, size, 90, 0);
mPath.rQuadTo(20, -size, 90, 0);
}
mPath.close();
mCanvasBitmap.drawPath(mPath, mPaintWave);
canvas.drawBitmap(mBitmapBubble, 0, 0, null);
//绘制文本,当前进度
canvas.drawText(progress*100/maxProgress+"%",width/2,height/2,mPaintText);
}
}
主活动调用自定义View:
public class MainActivity extends Activity {
private int progress;
private Button mButtonStart;
private MyPathView myPathView;
private static final int DOWNLOAD_UPDATE = 0x99;
//模拟下载
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//处理msg
switch (msg.what) {
case DOWNLOAD_UPDATE:
progress += 1;
//当progress大于maxProgress时,不再调用一下方法
if (progress<=myPathView.getMaxProgress()){
myPathView.setProgress(progress);//设置新的进度
sendEmptyMessageDelayed(DOWNLOAD_UPDATE, 100);//每隔100毫秒发送一次handler
}
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStart = (Button) findViewById(R.id.button_start);
myPathView = (MyPathView) findViewById(R.id.progress_view_first);
mButtonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//向handler发送一个延时空消息,1000毫秒后发送
mHandler.sendEmptyMessageDelayed(DOWNLOAD_UPDATE, 1000);
}
});
}
}
布局调用自定义View:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Download"/>
<com.example.administrator.selfdefinedview.widget.MyPathView
android:id="@+id/progress_view_first"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
我们猿类工作压力大,很需要有自己的乐趣,于是乎,我开通了音乐人账号,以后的作品将会上传到我的音乐人小站上。如果这篇博客帮助到您,希望您能多关注,支持,鼓励我将创作进行下去,同时也祝你能在工作和生活乐趣两发面都能出彩!
如果这篇博客帮助到您,您可以完成以下操作:
在网易云搜索“星河河”->歌手->点击进入(您将进入我的网易云音乐人账号星河河)->关注我->多听听我的歌。
豆瓣音乐人地址:https://site.douban.com/chuxinghe/ 星河河