Android自定義等待對話框
最近,看了好多的APP的等待對話框,發(fā)現(xiàn)自己的太lower,于是就研究了一番,最后經(jīng)過苦心努力,實(shí)現(xiàn)一個(gè)。
- 自定義一個(gè)LoadingIndicatorView(extends View )類
- 編寫values/attrs.xml,在其中編寫styleable和item等標(biāo)簽元素
- 在布局文件中LoadingIndicatorView使用自定義的屬性(注意namespace)
- 在LoadingIndicatorView的構(gòu)造方法中通過TypedArray獲取
描述就提供這些,一下是代碼的展示,非常的詳細(xì)。
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);//設(shè)置畫筆的顏色 mPaint.setStyle(Paint.Style.FILL);//設(shè)置畫筆的樣式為填充 mPaint.setAntiAlias(true);//去鋸齒 applyIndicator();// } private void applyIndicator(){ switch (mIndicatorId){ case BallSpinFadeLoader: mIndicatorController=new BallSpinFadeLoaderIndicator(); break; } mIndicatorController.setTarget(this);//將控件設(shè)置到當(dāng)前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 默認(rèn)大小 * @param measureSpec {@see widthMeasureSpec,heightMeasureSpec} * @return 返回測量的結(jié)果 */ private int measureDimension(int defaultSize,int measureSpec){ int result = defaultSize; int specMode = MeasureSpec.getMode(measureSpec);//測量規(guī)范 int specSize = MeasureSpec.getSize(measureSpec);//測量大小 if (specMode == MeasureSpec.EXACTLY) {//父控件已經(jīng)為子控件設(shè)置確定的大小,子控件會(huì)考慮父控件給他的大小,自己需要多大設(shè)置多大 result = specSize; } else if (specMode == MeasureSpec.AT_MOST) {//子控件可以設(shè)置自己希望的指定大小 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. * 創(chuàng)建動(dòng)畫或者動(dòng)畫集合,添加到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; /** * 圓點(diǎn)的比例 */ float[] scaleFloats=new float[]{SCALE, SCALE, SCALE, SCALE, SCALE, SCALE, SCALE, SCALE}; /** * 圓點(diǎn)的透明度集合 */ 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,點(diǎn)A與到X軸的為角α. *則點(diǎn)A的坐標(biāo)為(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);//創(chuàng)建ValueAnimator對象 scaleAnim.setDuration(1000);//設(shè)置動(dòng)畫的持續(xù)時(shí)間 scaleAnim.setRepeatCount(-1);//設(shè)置動(dòng)畫是否重復(fù) scaleAnim.setStartDelay(delays[i]);//延遲啟動(dòng)動(dòng)畫 scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {//ValueAnimator只負(fù)責(zé)第一次的內(nèi)容,因此必須通過監(jiān)聽來實(shí)現(xiàn)對象的相關(guān)屬性的更新 @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue();//獲取當(dāng)前幀的值 postInvalidate(); } }); scaleAnim.start();//啟動(dòng)屬性動(dòng)畫 ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 77, 255);//透明度動(dòng)畫 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; /** * 對話框的實(shí)現(xiàn) * @author 李東 * @Date 2014-11-23 */ public class UIHelper { /** 加載數(shù)據(jù)對話框 */ private static Dialog mLoadingDialog; /** * 顯示加載對話框 * @param context 上下文 * @param msg 對話框顯示內(nèi)容 * @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(); } /** * 關(guān)閉加載對話框 */ 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); } }
效果圖;
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
相關(guān)文章
Flutter實(shí)現(xiàn)增強(qiáng)版的頁面懸浮按鈕的示例代碼
Flutter?自帶的?FloatingActionButton?為我們提供了一個(gè)懸浮在頂部的按鈕,這個(gè)按鈕始終在最頂層,因此可以做一些快捷的操作。本文就來和大家詳細(xì)聊聊2023-01-01Android 后臺運(yùn)行白名單實(shí)現(xiàn)?;?/a>
這篇文章主要介紹了Android 后臺運(yùn)行白名單實(shí)現(xiàn)?;?,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12Android控件ToggleButton多狀態(tài)按鈕使用詳解
這篇文章主要為大家詳細(xì)介紹了Android控件ToggleButton多狀態(tài)按鈕的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Android編程之非調(diào)用系統(tǒng)界面實(shí)現(xiàn)發(fā)送彩信的方法(MMS)
這篇文章主要介紹了Android編程之非調(diào)用系統(tǒng)界面實(shí)現(xiàn)發(fā)送彩信的方法,涉及Android源碼中的mms的使用技巧,需要的朋友可以參考下2016-01-01分享10個(gè)很棒的學(xué)習(xí)Android開發(fā)的網(wǎng)站
我推薦的網(wǎng)站,都是我在學(xué)習(xí)Android 開發(fā)過程中發(fā)現(xiàn)的好網(wǎng)站,給初學(xué)者一些建議,少走一些彎路2015-03-03Android自定義view Path 的高級用法之搜索按鈕動(dòng)畫
這篇文章主要介紹了Android自定義view Path 的高級用法之搜索按鈕動(dòng)畫,需要的朋友可以參考下2017-06-06android底部彈出iOS7風(fēng)格對話選項(xiàng)框(QQ對話框)--第三方開源之IOS_Dialog_Library
這篇文章主要介紹了android底部彈出iOS7風(fēng)格對話選項(xiàng)框(QQ對話框)--第三方開源--IOS_Dialog_Library的相關(guān)資料,需要的朋友可以參考下2015-11-11Android 藍(lán)牙開發(fā)實(shí)例解析
本文主要介紹Android 藍(lán)牙開發(fā),這里提供實(shí)例代碼和詳細(xì)解析實(shí)現(xiàn)方法,對開發(fā)Android藍(lán)牙開發(fā)的朋友提供簡單示例,有需要的朋友可以參考下2016-08-08利用百度地圖Android sdk高仿微信發(fā)送位置功能及遇到的問題
這篇文章給大家介紹了利用百度地圖Android sdk高仿微信發(fā)送位置功能,在實(shí)現(xiàn)此功能的時(shí)候遇到點(diǎn)小問題,下面小編給大家列出來,需要的朋友參考下吧2017-12-12