Android自定义等待对话框
程序员文章站
2024-02-26 20:28:10
最近,看了好多的app的等待对话框,发现自己的太lower,于是就研究了一番,最后经过苦心努力,实现一个。
自定义一个loadingindicatorview(e...
最近,看了好多的app的等待对话框,发现自己的太lower,于是就研究了一番,最后经过苦心努力,实现一个。
- 自定义一个loadingindicatorview(extends view )类
- 编写values/attrs.xml,在其中编写styleable和item等标签元素
- 在布局文件中loadingindicatorview使用自定义的属性(注意namespace)
- 在loadingindicatorview的构造方法中通过typedarray获取
描述就提供这些,一下是代码的展示,非常的详细。
1、自定义属性的声明文件
<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
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
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
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
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(); } } }
对话框的布局:
<?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>
对话框的样式:
<!-- 自定义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
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); } }
效果图;
以上就是本文的全部内容,希望对大家的学习有所帮助。
上一篇: servlet转发、包含详解(七)
推荐阅读
-
Android自定义ViewGroup横向布局(1)
-
Android三种方式实现ProgressBar自定义圆形进度条
-
Android自定义viewgroup 使用adapter适配数据(6)
-
Android自定义viewgroup快速滑动(4)
-
Android中自定义水平进度条样式之黑色虚线
-
Android自定义ViewGroup实现受边界限制的滚动操作(3)
-
Android自定义viewgroup可滚动布局 GestureDetector手势监听(5)
-
Android开发之利用Activity实现Dialog对话框
-
Android自定义相机实现自动对焦和手动对焦
-
Android自定义带水滴的进度条样式(带渐变色效果)