Android自定义等待对话框

最近,看了好多的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);
  } 

} 

效果图;

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

(0)

相关推荐

  • Android实现自定义圆角对话框Dialog的示例代码

    前言: 项目中多处用到对话框,用系统对话框太难看,就自己写一个自定义对话框. 对话框包括:1.圆角 2.app图标 , 提示文本,关闭对话框的"确定"按钮 难点:1.对话框边框圆角显示 2.考虑到提示文本字数不确定,在不影响美观的情况下,需要在一行内显示提示的文字信息 3.设置对话框的宽和高 技术储备: 1.安卓开发_使用AlertDialog实现对话框    知道AlertDialog有setView(view) ,Dialog 有ContentView(view) 方法. 2.An

  • Android中制作自定义dialog对话框的实例分享

    自定义dialog基础版 很多时候,我们在使用android sdk提供的alerdialog的时候,会因为你的系统的不同而产生不同的效果,就好比如你刷的是MIUI的系统,弹出框都会在顶部显示!这里简单的介绍自定义弹出框的应用. 首先创建布局文件dialog: 代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.and

  • Android对话框自定义标题 对话框标题美化操作

    Android自带的对话框标题不好看,如果我们需要给弹出的对话框设置一个自己定义的标题,可以使用AlertDialog.Builder的setCustomTitle()方法. 定义一个对话框标题的title.xml文件: <?xml version="1.0" encoding="UTF-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android

  • Android自定义控件实现万能的对话框

    自定义控件有段时间没更新了,今天给大家带来一个新的对话框样式,本着用更少的代码实现更丰富的功能. 由于对话框对用户的操作有影响,所以目前app上的对话框用的已经比较少了,但还是有一些比较重要的信息提示需要使用对话框的样式,例如版本更新,账户异地登陆等. 下面来看自定义对话框的样式: 图1:自定义提示对话框 图2:自定义警告对话框 图3:默认提示对话框 图4:默认警告对话框 这里面带来了两种对话框的样式,也是比较常见的.以上所有的背景颜色,文字颜色,以及按钮的点击效果都是可以自定义的. 下面分别看

  • Android中自定义对话框(Dialog)的实例代码

    1.修改系统默认的Dialog样式(风格.主题) 2.自定义Dialog布局文件 3.可以自己封装一个类,继承自Dialog或者直接使用Dialog类来实现,为了方便以后重复使用,建议自己封装一个Dialog类 第一步: 我们知道Android定义个控件或View的样式都是通过定义其style来实现的,查看Android框架中的主题文件,在源码中的路径:/frameworks/base/core/res/res/values/themes.xml,我们可以看到,Android为Dialog定义了

  • Android自定义对话框Dialog

    本文简单介绍自定义对话框Dialog的使用,代码和结构都非常简单,目的是能够快速使用自定义对话框,在本文中不具体讲解对话框的高级使用. 实现步骤 首先需要自己在我们的.xml文件中自己构建布局 布局文件做好之后,我们可以在style文件下自己定义布局的样式 前两步都做好之后,我开始在写java文件 具体实现过程 1.   xml文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns

  • Android如何自定义升级对话框示例详解

    前言 本文主要给大家介绍了关于Android自定义升级对话框的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 实现的效果如下所示 其实这也只是一个DialogFragment 而已,重点只是在于界面的设计 想要使用做出这样一个DialogFragment ,需要自定义一个View,然后将该View传入到该Dialog中 先定义布局,一个TextView用于标题,一个TextView用于升级内容阐述,一个ImageView,一个确认升级的按钮 <?xml version

  • Android自定义等待对话框

    最近,看了好多的APP的等待对话框,发现自己的太lower,于是就研究了一番,最后经过苦心努力,实现一个. 自定义一个LoadingIndicatorView(extends View )类 编写values/attrs.xml,在其中编写styleable和item等标签元素 在布局文件中LoadingIndicatorView使用自定义的属性(注意namespace) 在LoadingIndicatorView的构造方法中通过TypedArray获取 描述就提供这些,一下是代码的展示,非常的

  • Android 自定义AlertDialog对话框样式

    实际的项目开发当中,经常需要根据实际的需求来自定义AlertDialog.最近在开发一个WIFI连接的功能,点击WIFI需要弹出自定义密码输入框.在此权当记录 效果图 点击首页的Button即跳出对话框,显示WIFI信息(TextView),密码输入框(EditText),取消和连接按钮(Button) 实现 根据自己实际的需求,为AlertDialog创建一个布局,在此我需要定义一个如图所示的WIFI密码输入框,故在 res/layout 目录下建立一个 dialog_layout.xml 文

  • android自定义AlertDialog对话框

    前面一篇文章http://www.jb51.net/article/103036.htm介绍了alertDialog的四种简单使用,但是有些时候为了让整个app的风格统一,或者说前面的四种形式不符合项目中的需求,这个时候就需要我们自定义alertDialog了.直接上代码 CustomAlertDialog: import android.app.Dialog; import android.content.Context; import android.os.Bundle; import an

  • Android 自定义弹出菜单和对话框功能实例代码

    Android 开发当中,可能会存在许多自定义布局的需求,比如自定义弹出菜单(popupWindow),以及自定义对话框(Dialog). 话不多说,直接上图片. 先讲第一种,自定义PopUpWindow 1.popupWindow protected void showPopWindow(View view, final int pos){ WindowManager wm= (WindowManager) myContext.getSystemService(Context.WINDOW_S

  • Android 自定义对话框 showSetPwdDialog

    样式如下所示: 布局: layout dialog_set_pwd.xml <?xml version="." encoding="utf-"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height=&

  • Android自定义Dialog实现加载对话框效果

    前言 最近开发中用到许多对话框,之前都是在外面的代码中创建AlertDialog并设置自定义布局实现常见的对话框,诸如更新提示等含有取消和删除两个按钮的对话框我们可以通过代码创建一个AlertDialog并通过它暴露的一系列方法设置我们自定义的布局和style,但有时候系统的AlertDialog并不能实现更好的定制,这时,我们就想到了自定义Dialog.通过查看AlertDialog的类结构发现它也是继承于Dialog,于是我们也可以通过继承Dialog实现我们自定义的Dialog.这篇文章将

  • Android自定义PopupWindow实现炫酷的IOS对话框效果

    前言: 最近在使用IOS系统的过程中发现IOS底部弹出框甚是漂亮,大气,上档次,于是乎就想啊能不能在Android中实现类似的对话框呢?你说,这不是废话吗,除了一些极少数的系统级的不能模仿外(版权)还有啥不能依瓢画葫芦的呢,所以啊,这篇文章将介绍如何在Android中实现高仿IOS对话框效果,先上图,给大家养养眼: 大家在看到上面的对话框时有没有想到简单的实现思路呢?我这里给出的思路是我们可以自定义一个PopupWindow,然后设置我们的布局.这里的布局很有技巧哦,那就是对话框中间的透明隔断区

  • android自定义带箭头对话框

    本文实例为大家分享了android自定义带箭头对话框的具体代码,供大家参考,具体内容如下 import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.support.annotation.Nullabl

  • android自定义对话框实例代码

    1.实现效果    2.定义dialog.xml (res/layout/dialog.xml) <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android

随机推荐