Builder模式打造通用Dialog效果
阿新 • • 發佈:2018-12-16
這是參照系統Dialog,採用Builder模式實現的一個萬能dialog效果;
參照系統dialog的方式,涉及到AlertDialog、DialogViewHelper、AlertController這三個類, AlertDialog類中主要提供了一些dialog樣式、效果、佈局等設定的方法,採用Builder的設計模式,在使用的時候可以採用鏈式呼叫;
參照系統dialog的方式,涉及到AlertDialog、DialogViewHelper、AlertController這三個類, AlertDialog類中主要提供了一些dialog樣式、效果、佈局等設定的方法,採用Builder的設計模式,在使用的時候可以採用鏈式呼叫;
AlertController類是萬能dialog效果實現的一個控制類, AlertController類中有提供了一個AlertParams內部類,在AlertParams內部類的apply方法中進行dialog引數的繫結和設定;package com.dialogdemo.dialog; import android.app.Dialog; import android.content.Context; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import com.dialogdemo.R; /** * Created by Administrator on 2017/5/21. * 自定義dialog */ public class AlertDialog extends Dialog { private AlertController mAlert; public AlertDialog(Context context, int themeResId) { super(context, themeResId); mAlert = new AlertController(this, getWindow()); } /** * 設定文字 * * @param viewid * @param text */ public void setText(int viewid, CharSequence text) { mAlert.setText(viewid, text); } public <T extends View> T getView(int viewid) { return mAlert.getView(viewid); } /** * 設定點選 * * @param viewid * @param listener */ public void setOnClickListener(int viewid, View.OnClickListener listener) { mAlert.setOnClickListener(viewid, listener); } public static class Builder { private AlertController.AlertParams P; public Builder(Context context) { this(context, R.style.dialog);//預設樣式 } public Builder(Context context, int themeResId) { P = new AlertController.AlertParams(context, themeResId); } public AlertDialog create() { final AlertDialog dialog = new AlertDialog(P.mContext, P.mThemeResId); P.apply(dialog.mAlert); dialog.setCancelable(P.mCancelable); if (P.mCancelable) { dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(P.mOnCancelListener); dialog.setOnDismissListener(P.mOnDismissListener); if (P.mOnKeyListener != null) { dialog.setOnKeyListener(P.mOnKeyListener); } return dialog; } /** * 設定佈局 * * @param v * @return */ public Builder setContentView(View v) { P.mView = v; P.mViewLayoutResId = 0; return this; } /** * 設定佈局 * * @param layoutId * @return */ public Builder setContentView(int layoutId) { P.mView = null; P.mViewLayoutResId = layoutId; return this; } /** * 設定文字 * * @param viewId * @param text * @return */ public Builder setText(int viewId, CharSequence text) { P.mTextArray.put(viewId, text); return this; } /** * 設定點選 * * @param view * @param listener * @return */ public Builder setOnClickListener(int view, View.OnClickListener listener) { P.mClickArray.put(view, listener); return this; } //配置一些萬能的引數 /** * 全屏 * * @return */ public Builder fullWith() { P.mWith = ViewGroup.LayoutParams.MATCH_PARENT; return this; } /** * 從底部彈出是否有動畫 * * @param isAnimation * @return */ public Builder formBottom(boolean isAnimation) { if (isAnimation) { P.mAnimation = R.style.dialog_from_bottom_anim; } P.mGravity = Gravity.BOTTOM; return this; } /** * 設定寬高 * * @param with * @param height * @return */ public Builder setWithAndHeight(int with, int height) { P.mWith = with; P.mHeight = height; return this; } /** * 新增預設動畫 * * @return */ public Builder addDefaultAinmation() { P.mAnimation = R.style.dialog_scale_anim; return this; } /** * 新增動畫 * * @return */ public Builder setAinmation(int styleAnimation) { P.mAnimation = styleAnimation; return this; } public Builder setOnCancelListener(OnCancelListener onCancelListener) { P.mOnCancelListener = onCancelListener; return this; } public Builder setOnDismissListener(OnDismissListener onDismissListener) { P.mOnDismissListener = onDismissListener; return this; } public Builder setOnKeyListener(OnKeyListener onKeyListener) { P.mOnKeyListener = onKeyListener; return this; } public Builder setCancelable(boolean cancelable) { P.mCancelable = cancelable; return this; } public AlertDialog show() { final AlertDialog dialog = create(); dialog.show(); return dialog; } } }
package com.dialogdemo.dialog; import android.content.Context; import android.content.DialogInterface; import android.util.SparseArray; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; /** * Created by Administrator on 2017/5/21. */ class AlertController { private AlertDialog mAlertDialog; private Window mWindow; private DialogViewHelper mViewHelper; /** * 獲取AlertDialog * * @return */ public AlertDialog getDialog() { return mAlertDialog; } /** * 獲取AlertDialog的Window * * @return */ public Window getWindow() { return mWindow; } public AlertController(AlertDialog alertDialog, Window window) { this.mAlertDialog = alertDialog; this.mWindow = window; } public void setViewHelper(DialogViewHelper mViewHelper) { this.mViewHelper = mViewHelper; } /** * 設定文字 * * @param viewid * @param text */ public void setText(int viewid, CharSequence text) { mViewHelper.setText(viewid, text); } public <T extends View> T getView(int viewid) { return mViewHelper.getView(viewid); } /** * 設定點選 * * @param viewid * @param listener */ public void setOnClickListener(int viewid, View.OnClickListener listener) { mViewHelper.setOnClickListener(viewid, listener); } public static class AlertParams { public Context mContext; public int mThemeResId; public boolean mCancelable = true;//點選空白是否可以取消 public DialogInterface.OnCancelListener mOnCancelListener;//AlertDialog取消監聽 public DialogInterface.OnDismissListener mOnDismissListener;//AlertDialog消失監聽 public DialogInterface.OnKeyListener mOnKeyListener;//AlertDialog消失監聽按鍵監聽 public View mView;//顯示的佈局 public int mViewLayoutResId;//佈局id //there can be gaps in the indices. It is intended to be more memory efficient //* than using a HashMap to map Integers to Objects, both because it avoids //存放字型的修改 public SparseArray<CharSequence> mTextArray = new SparseArray<CharSequence>(); //存放點選事件 public SparseArray<View.OnClickListener> mClickArray = new SparseArray<View.OnClickListener>(); //預設寬度 public int mWith = ViewGroup.LayoutParams.WRAP_CONTENT; //動畫 public int mAnimation = 0; //位置預設居中 public int mGravity = Gravity.CENTER; //預設高度 public int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT; public AlertParams(Context context, int themeResId) { this.mContext = context; this.mThemeResId = themeResId; } /** * 繫結和設定引數 * * @param mAlert */ public void apply(AlertController mAlert) { //設定引數 //1設定佈局 DialogViewHelper viewHelper = null; if (mViewLayoutResId != 0) { viewHelper = new DialogViewHelper(mContext, mViewLayoutResId); } if (mView != null) { viewHelper = new DialogViewHelper(); viewHelper.setContentView(mView); } if (viewHelper == null) { throw new IllegalArgumentException("viewHelper is null"); } //給dialog設定佈局 mAlert.getDialog().setContentView(viewHelper.getContentView()); //設定AlertController輔助類 mAlert.setViewHelper(viewHelper); //2設定文字 int mTextSize = mTextArray.size(); for (int i = 0; i < mTextSize; i++) { mAlert.setText(mTextArray.keyAt(i), mTextArray.valueAt(i)); } //3設定點選 int mClickSize = mClickArray.size(); for (int i = 0; i < mClickSize; i++) { mAlert.setOnClickListener(mClickArray.keyAt(i), mClickArray.valueAt(i)); } //4設定自定效果 全屏 從底部彈出 預設動畫 Window window = mAlert.getWindow(); //設定位置 window.setGravity(mGravity); //設定動畫 if (mAnimation != 0) { window.setWindowAnimations(mAnimation); } //設定寬高 WindowManager.LayoutParams attributes = window.getAttributes(); attributes.width = mWith; attributes.height = mHeight; window.setAttributes(attributes); } } }
最後剩下DialogViewHelper類,這個類比較簡單,就是一個輔助類,用於佈局的例項化載入,佈局中view的快取及設定一些點選事件等;
package com.dialogdemo.dialog; import android.content.Context; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import java.lang.ref.WeakReference; /** * Created by Administrator on 2017/5/21. * AlertDialog View 的輔助處理類 */ class DialogViewHelper { private View mContentView = null; //用於快取佈局中的view private SparseArray<WeakReference<View>> mViews; public DialogViewHelper(Context mContext, int mViewLayoutResId) { this(); //例項化解析載入佈局檔案 mContentView = LayoutInflater.from(mContext).inflate(mViewLayoutResId, null); } public DialogViewHelper() { mViews = new SparseArray<>(); } /** * 設定佈局 * * @param contentView */ public void setContentView(View contentView) { this.mContentView = contentView; } /** * 設定文字 * * @param viewid * @param text */ public void setText(int viewid, CharSequence text) { TextView tv = getView(viewid); if (tv != null) { tv.setText("" + text); } } public <T extends View> T getView(int viewid) { WeakReference<View> viewWeakReference = mViews.get(viewid); View view = null; if (viewWeakReference != null) { view = viewWeakReference.get(); } if (view == null) { view = mContentView.findViewById(viewid); if (view != null) { mViews.put(viewid, new WeakReference<View>(view)); } } return (T) view; } /** * 設定點選 * * @param viewid * @param listener */ public void setOnClickListener(int viewid, View.OnClickListener listener) { View view = getView(viewid); if (view != null) { view.setOnClickListener(listener); } } /** * 獲取contentView * * @return */ public View getContentView() { return mContentView; } }
接下來說下簡單的呼叫:
private void thridView() {
List<String> list = new ArrayList();
for (int i = 0; i < 5; i++) {
list.add("item" + i);
}
AlertDialog dialog = new AlertDialog.Builder(this)
.setContentView(R.layout.thrid_layout)
.setCancelable(true)
.show();
RecyclerView recyclerView = dialog.getView(R.id.recycler_view);
//設定佈局管理器
recyclerView.setLayoutManager(new LinearLayoutManager(this));
DialogListAdapter adapter = new DialogListAdapter(list, this);
recyclerView.setAdapter(adapter);
}
這樣就實現了dialog列表的效果,是不是感覺呼叫很簡單。
原始碼地址:
https://pan.baidu.com/s/1MuJcrcBYLox4dFud_tJ9kg