Android自定义等待对话框

时间:2022-04-10 07:54:10

最近,看了好多的app的等待对话框,发现自己的太lower,于是就研究了一番,最后经过苦心努力,实现一个。

  • 自定义一个loadingindicatorview(extends view )类
  • 编写values/attrs.xml,在其中编写styleable和item等标签元素
  • 在布局文件中loadingindicatorview使用自定义的属性(注意namespace)
  • 在loadingindicatorview的构造方法中通过typedarray获取

描述就提供这些,一下是代码的展示,非常的详细。
1、自定义属性的声明文件

?
1
2
3
4
5
6
7
8
9
<declare-styleable name="avloadingindicatorview">
    <attr name="indicator">
      <flag name="ballspinfadeloader" value="22"/>
    </attr>
    <attr name="indicator_color" format="color"/>
  </declare-styleable>
 
 
<pre name="code" class="html">

loadingindicatorview.java 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import android.annotation.targetapi;
import android.content.context;
import android.content.res.typedarray;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.os.build;
import android.support.annotation.intdef;
import android.util.attributeset;
import android.view.view;
 
import com.chni.lidong.androidtestdemo.r;
 
 
/**
 * created by lidongon 2016/1/31
 *
 .ballspinfadeloader,
 *
 */
public class loadingindicatorview extends view {
 
 
  //indicators 指示器
  public static final int ballspinfadeloader=22;
 
  @intdef(flag = true,
      value = {
          ballspinfadeloader,
      })
  public @interface indicator{}
 
  //sizes (with defaults in dp)
  public static final int default_size=45;
 
  //attrs
  int mindicatorid;
  int mindicatorcolor;
 
  paint mpaint;
 
  baseindicatorcontroller mindicatorcontroller;
 
  private boolean mhasanimation;
 
 
  public loadingindicatorview(context context) {
    super(context);
    init(null, 0);
  }
 
  public loadingindicatorview(context context, attributeset attrs) {
    super(context, attrs);
    init(attrs, 0);
  }
 
  public loadingindicatorview(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);
    init(attrs, defstyleattr);
  }
 
 
  @targetapi(build.version_codes.lollipop)
  public loadingindicatorview(context context, attributeset attrs, int defstyleattr, int defstyleres) {
    super(context, attrs, defstyleattr, defstyleres);
    init(attrs, defstyleattr);
  }
 
  private void init(attributeset attrs, int defstyle) {
    /**
     *获取typedarray(属性的集合)
     */
    typedarray a = getcontext().obtainstyledattributes(attrs, r.styleable.avloadingindicatorview);
    mindicatorid=a.getint(r.styleable.avloadingindicatorview_indicator, ballspinfadeloader);//获取编号属性
    mindicatorcolor=a.getcolor(r.styleable.avloadingindicatorview_indicator_color, color.white);//获取颜色属性
    a.recycle();//回收属性的集合
    mpaint=new paint();
    mpaint.setcolor(mindicatorcolor);//设置画笔的颜色
    mpaint.setstyle(paint.style.fill);//设置画笔的样式为填充
    mpaint.setantialias(true);//去锯齿
    applyindicator();//
  }
 
  private void applyindicator(){
    switch (mindicatorid){
      case ballspinfadeloader:
        mindicatorcontroller=new ballspinfadeloaderindicator();
        break;
    }
    mindicatorcontroller.settarget(this);//将控件设置到当前view
  }
 
  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    int width = measuredimension(dp2px(default_size), widthmeasurespec);//获取view的宽度
    int height = measuredimension(dp2px(default_size), heightmeasurespec);//获取view的高度
    setmeasureddimension(width, height);//
  }
 
  /**
   *测量的 维度
   * @param defaultsize 默认大小
   * @param measurespec {@see widthmeasurespec,heightmeasurespec}
   * @return 返回测量的结果
   */
  private int measuredimension(int defaultsize,int measurespec){
    int result = defaultsize;
    int specmode = measurespec.getmode(measurespec);//测量规范
    int specsize = measurespec.getsize(measurespec);//测量大小
    if (specmode == measurespec.exactly) {//父控件已经为子控件设置确定的大小,子控件会考虑父控件给他的大小,自己需要多大设置多大
      result = specsize;
    } else if (specmode == measurespec.at_most) {//子控件可以设置自己希望的指定大小
      result = math.min(defaultsize, specsize);//取最小值
    } else {
      result = defaultsize;
    }
    return result;
  }
 
  @override
  protected void ondraw(canvas canvas) {
    super.ondraw(canvas);
    drawindicator(canvas);
  }
 
  @override
  protected void onlayout(boolean changed, int left, int top, int right, int bottom) {
    super.onlayout(changed, left, top, right, bottom);
    if (!mhasanimation){
      mhasanimation=true;
      applyanimation();
    }
  }
 
  void drawindicator(canvas canvas){
    mindicatorcontroller.draw(canvas,mpaint);
  }
 
  void applyanimation(){
    mindicatorcontroller.createanimation();
  }
 
  private int dp2px(int dpvalue) {
    return (int) getcontext().getresources().getdisplaymetrics().density * dpvalue;
  }

baseindicatorcontroller.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.chni.lidong.androidtestdemo.loading;
 
import android.graphics.canvas;
import android.graphics.paint;
import android.view.view;
 
/**
 * created by lidongon 2016/1/31
 */
public abstract class baseindicatorcontroller {
 
  private view mtarget;
 
 
  public void settarget(view target){
    this.mtarget=target;
  }
 
  public view gettarget(){
    return mtarget;
  }
 
  /**
   * 得到view的宽度
   * @return
   */
  public int getwidth(){
    return mtarget.getwidth();
  }
 
  /**
   * 得到view的高度
   * @return
   */
  public int getheight(){
    return mtarget.getheight();
  }
 
  /**
   * 刷新view
   */
  public void postinvalidate(){
    mtarget.postinvalidate();
  }
 
  /**
   * draw indicator what ever
   * you want to draw
   * 绘制indicate
   * @param canvas
   * @param paint
   */
  public abstract void draw(canvas canvas,paint paint);
 
  /**
   * create animation or animations
   * ,and add to your indicator.
   * 创建动画或者动画集合,添加到indcator
   */
  public abstract void createanimation();
 
 
}

 ballspinfadeloaderindicator.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package com.chni.lidong.androidtestdemo.loading;
 
import android.graphics.canvas;
import android.graphics.paint;
 
import com.nineoldandroids.animation.valueanimator;
 
/**
 * created by lidongon 2016/1/31
 */
public class ballspinfadeloaderindicator extends baseindicatorcontroller {
 
  public static final float scale=1.0f;
 
  public static final int alpha=255;
  /**
   * 圆点的比例
   */
  float[] scalefloats=new float[]{scale,
      scale,
      scale,
      scale,
      scale,
      scale,
      scale,
      scale};
  /**
   * 圆点的透明度集合
   */
  int[] alphas=new int[]{alpha,
      alpha,
      alpha,
      alpha,
      alpha,
      alpha,
      alpha,
      alpha};
 
 
  @override
  public void draw(canvas canvas, paint paint) {
    float radius=getwidth()/10;
    for (int i = 0; i < 8; i++) {
      canvas.save();
      point point=circleat(getwidth(),getheight(),getwidth()/2-radius,i*(math.pi/4));
      canvas.translate(point.x,point.y);
      canvas.scale(scalefloats[i],scalefloats[i]);
      paint.setalpha(alphas[i]);
      canvas.drawcircle(0,0,radius,paint);
      canvas.restore();
    }
  }
 
  /**
   * 圆o的圆心为(a,b),半径为r,点a与到x轴的为角α.
   *则点a的坐标为(a+r*cosα,b+r*sinα)
   * @param width
   * @param height
   * @param radius
   * @param angle
   * @return
   */
  point circleat(int width,int height,float radius,double angle){
    float x= (float) (width/2+radius*(math.cos(angle)));
    float y= (float) (height/2+radius*(math.sin(angle)));
    return new point(x,y);
  }
 
  @override
  public void createanimation() {
    int[] delays= {0, 120, 240, 360, 480, 600, 720, 780, 840};
    for (int i = 0; i < 8; i++) {
      final int index=i;
      valueanimator scaleanim=valueanimator.offloat(1,0.4f,1);//创建valueanimator对象
      scaleanim.setduration(1000);//设置动画的持续时间
      scaleanim.setrepeatcount(-1);//设置动画是否重复
      scaleanim.setstartdelay(delays[i]);//延迟启动动画
      scaleanim.addupdatelistener(new valueanimator.animatorupdatelistener() {//valueanimator只负责第一次的内容,因此必须通过监听来实现对象的相关属性的更新
        @override
        public void onanimationupdate(valueanimator animation) {
          scalefloats[index] = (float) animation.getanimatedvalue();//获取当前帧的值
          postinvalidate();
        }
      });
      scaleanim.start();//启动属性动画
 
      valueanimator alphaanim=valueanimator.ofint(255, 77, 255);//透明度动画
      alphaanim.setduration(1000);//
      alphaanim.setrepeatcount(-1);
      alphaanim.setstartdelay(delays[i]);
      alphaanim.addupdatelistener(new valueanimator.animatorupdatelistener() {
        @override
        public void onanimationupdate(valueanimator animation) {
          alphas[index] = (int) animation.getanimatedvalue();
          postinvalidate();
        }
      });
      alphaanim.start();
    }
  }
 
  final class point{
    public float x;
    public float y;
 
    public point(float x, float y){
      this.x=x;
      this.y=y;
    }
  }
 
 
}

uihelp.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.chni.lidong.androidtestdemo.utils;
 
import android.app.activity;
import android.app.dialog;
import android.view.layoutinflater;
import android.view.view;
import android.widget.linearlayout;
import android.widget.textview;
 
import com.chni.lidong.androidtestdemo.r;
 
/**
 * 对话框的实现
 * @author 李东
 * @date 2014-11-23
 */
public class uihelper {
   
  /** 加载数据对话框 */
  private static dialog mloadingdialog;
   
   
  /**
   * 显示加载对话框
   * @param context 上下文
   * @param msg 对话框显示内容
   * @param cancelable 对话框是否可以取消
   */
  public static void showdialogforloading(activity context, string msg, boolean cancelable) {
    view view = layoutinflater.from(context).inflate(r.layout.layout_loading_dialog, null);
    textview loadingtext = (textview)view.findviewbyid(r.id.id_tv_loading_dialog_text);
    loadingtext.settext(msg);
     
    mloadingdialog = new dialog(context, r.style.loading_dialog_style);
    mloadingdialog.setcancelable(cancelable);
    mloadingdialog.setcontentview(view, new linearlayout.layoutparams(linearlayout.layoutparams.match_parent, linearlayout.layoutparams.match_parent));
    mloadingdialog.show();   
  }
   
  /**
   * 关闭加载对话框
   */
  public static void hidedialogforloading() {
    if(mloadingdialog != null && mloadingdialog.isshowing()) {
      mloadingdialog.cancel();
    }
  }
 
}

对话框的布局:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="@drawable/bg_loading_dialog_shape"
  android:gravity="center"
  android:minheight="60dp"
  android:minwidth="180dp"
  android:orientation="vertical"
  android:padding="@dimen/padding_10" >
 
  <linearlayout
    android:layout_width="wrap_content"
    android:layout_weight="1"
    android:gravity="center"
    android:layout_height="wrap_content">
 
    <com.chni.lidong.androidtestdemo.loading.avloadingindicatorview
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:indicator="ballspinfadeloader"
      app:indicator_color="@color/green"
      />
 
  </linearlayout>
 
  <textview
    android:id="@+id/id_tv_loading_dialog_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margintop="@dimen/padding_5"
    android:text="正在登录…"
    android:textcolor="@color/content"
    android:textsize="14sp" />
 
</linearlayout>

对话框的样式:

?
1
2
3
4
5
6
7
8
<!-- 自定义loading dialog -->
<style name="loading_dialog_style" parent="@android:style/theme.dialog">
  <item name="android:windowframe">@null</item>
  <item name="android:windownotitle">true</item>
  <item name="android:windowbackground">@color/transparent</item>
  <item name="android:windowisfloating">true</item>
  <item name="android:windowcontentoverlay">@null</item>
</style>

mainactivity.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class main7activity extends appcompatactivity {
 
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main7);
    toolbar toolbar = (toolbar) findviewbyid(r.id.toolbar);
    setsupportactionbar(toolbar);
 
    floatingactionbutton fab = (floatingactionbutton) findviewbyid(r.id.fab);
    fab.setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view view) {
        snackbar.make(view, "replace with your own action", snackbar.length_long)
            .setaction("action", null).show();
      }
    });
    uihelper.showdialogforloading(this, "正在加载...", true);
    handler handler = new handler();
    handler.postdelayed(new runnable() {
      @override
      public void run() {
        uihelper.hidedialogforloading();
      }
    },10000);
  }
 
}

效果图;

Android自定义等待对话框

以上就是本文的全部内容,希望对大家的学习有所帮助。