Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義等待對話框

Android自定義等待對話框

編輯:關於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); 
  } 
 
} 

效果圖;

以上就是本文的全部內容,希望對大家的學習有所幫助。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved