前言
这篇博客是接着前面的那一篇 的:
[仿南航app开发日记5]查成绩界面开发完成以及使用PopupWindow踩过的坑
效果
源码与原理
既然是自定义透明对话框,那么我直接选择继承Dialog,然后创建对话框,先看源码:
package cn.karent.nanhang.UI;
import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import cn.karent.nanhang.R;
/**
* Created by wan on 2016/12/27.
* 进度对话框
*/
public class ProgressDialog extends Dialog {
private ProgressDialog(Context context) {
super(context);
}
private ProgressDialog(Context context, int theme) {
super(context, theme);
}
public static class Builder {
private Context mContext;
public Builder(Context context) {
mContext = context;
}
public ProgressDialog create() {
ProgressDialog p = new ProgressDialog(mContext, R.style.LoginDialogTheme);
View v = LayoutInflater.from(mContext).inflate(R.layout.load_dialog_layout, null);
p.addContentView(v, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
Window window = p.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = 700;
lp.height = 700;
window.setAttributes(lp);
return p;
}
}
}
上面有定义高度和宽度,当然还设置了一个主题:
ProgressDialog p = new ProgressDialog(mContext, R.style.LoginDialogTheme);
至于这个主题,我在前面一篇创建登陆对话框时就使用过,我还是将sttyle放上来吧:
<style name="LoginDialogTheme" parent="Theme.AppCompat.DayNight.Dialog">
<item name="android:windowTitleStyle">@null</item>
<item name="android:windowBackground">@null</item>
</style>
这个style的功能就是去除了背景和标题,当然了,上面是继承Dialog,但是必须要自己写布局啊,布局如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<cn.karent.nanhang.UI.ProgressView
android:id="@+id/load_dialog_progressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:layout_marginTop="10dp"
android:text="正在加载中。。。"
android:textColor="#dfdbdb"/>
</LinearLayout>
</RelativeLayout>
依然是比较普通的布局文件,其中使用了一个自定义类,那就是
cn.karent.nanhang.UI.ProgressView
这个就是自定义进度条的核心了,我们看下源码:
package cn.karent.nanhang.UI;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PorterDuff;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.View;
import cn.karent.nanhang.R;
/**
* Created by wan on 2016/12/27.
* 重复绘制小圆点
*/
public class ProgressView extends View {
/**
* 全局上下文
*/
private Context mContext;
/**
* 图像变换矩阵
*/
private Matrix mMatrix = new Matrix();
/**
* 要绘制的背景图,也就是那个旋转的点点
*/
private Bitmap mBitmap;
/**
* 图片的宽度
*/
private int mWidth;
/**
* 图片的宽度
*/
private int mHeight;
public ProgressView(Context context) {
super(context);
}
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
//从资源加载bitmap对象
mBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.pic_dlg_loading);
mWidth = mBitmap.getWidth();
mHeight = mBitmap.getHeight();
//执行循环
new LoopAnimation().execute();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mMatrix.preRotate(6, mWidth / 2, mHeight / 2);
canvas.drawBitmap(mBitmap, mMatrix, null);
}
/**
* 循环动画,不停的触发旋转动画
*/
class LoopAnimation extends AsyncTask<Void, Void, Void> {
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
invalidate();
}
@Override
protected Void doInBackground(Void... params) {
int rotate = 0;
while( true ) {
try {
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
publishProgress();
}
}
}
}
看到了没,原理就是开个线程,然后不断的绘制一张图片,这里面有几点需要注意的地方:
mMatrix.preRotate(6, mWidth / 2, mHeight / 2);
这个是旋转的代码,必须知道图片的中心 (后面那两个参数),否则将会以原点为中心旋转,得到的结果绝对不是你想要的,另外还有一点需要注意,因为我们前面将对话框的背景去掉,所以默认不会清楚画布上面的内容,画出来的图形是不断叠加,在普通的java绘图当中我们的做法是在绘制任何东西之前先绘制一个白色背景,但是这里我们要绘制一个透明的背景:
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
这样就会清除原先绘制的背景 从而重新绘制了,好了,要点就是这么多。
我现在的测试的是直接在Activity的onCreate方法里面创建对话框,真正使用的时候可以先创建,然后在访问网络完成将对话框dismiss掉,代码如下:
new ProgressDialog.Builder(this).create().show();
上面的加载的是再ScoreActivity的onCreate方法里面,至于ScoreActivity是什么,我前面一篇博客有讲