之前實現了一個Demo
底部彈出框鼠渺,是用DialogFragment
實現的一個Dialog
,雖然實現了鏈式調用,但是沒有使用Builder
模式,所以想試試Builder
模式,寫博客記錄一下往堡。
這篇博客談論的Android
中的Builder
模式沒有Java
傳統的使用那么復雜,只是一種編程思路共耍,使需要復雜的參數構建的對象變得簡單,而且內部封裝構建過程可以方便變換和復用吨瞎,更是降低了耦合性痹兜。
分析 AlertDialog
AlertDialog
是谷歌原生的對話框,在V7包中提供了Material Design
設計風格的Dialog
颤诀,使用非常廣泛字旭。但是,在這篇博客里崖叫,我們只討論分析它的編程實現模式遗淳,它使用的就是Builder
模式。
1.先來看看 AlertDialog 源碼
從AlertDialog
源碼中可以發(fā)現成員變量中有一個AlertController
心傀,從它的命名
可以了解它大概是個組織類屈暗,即是所謂的”控制層“;再從AlertDialog
的構造方法中發(fā)現脂男,它沒做什么太多的操作养叛,主要就是初始化了AlertController
,那我們可以進一步了解到
AlertController
可能是擔任組織數據邏輯的作用宰翅。
那我們就進一步的看看
往下閱讀它的源碼弃甥,AlertDialog
在onCreate
中與AlertController
建立了聯系,從它的方法命名installContent()
可以了解它是初始化AlertDialog
內容實體的汁讼,那我們可以確定剛剛的推測淆攻,AlertController
是負責AlertDialog
組織內容邏輯的阔墩,而AlertDialog
只是簡單的”UI層“。
再往下就是AlertDialog
中靜態(tài)內部類瓶珊,也是我們要說的重點Builder
從Builder
類中發(fā)現了一個眼熟的東西——AlertController.AlertParams
,從它的命名(命名果然好重要)可以發(fā)現它可能是邏輯類啸箫,也就是”模型層“(是不是有點像MVC = =),負責處理數據邏輯的艰毒。
再看一看源碼
跟推測的一樣筐高,直接把數據賦予給了AlertController.AlertParams
,而且都是return Builder 對象丑瞧,保證了鏈式調用柑土;源碼里面大部分都是類似的代碼,這里只貼出部分绊汹。
在源碼的最后稽屏,發(fā)現了重點
在create()
方法中的apply()
是將AlertDialog
中的AlertController
與AlertController.AlertParams
建立聯系,其實就是控制層與邏輯層相通西乖,最后會由
AlertController
控制要顯示的視圖內容狐榔。
AlertDialog
的源碼基本上我們過了一遍,了解它的模式思路获雕,那我們再從apply()
進去薄腻,看看AlertController
與AlertController.AlertParams
是怎么建立聯系的。
2.AlertController.AlertParams源碼
從代碼中可以看見届案,AlertController
獲得了AlertController.AlertParams
中保存的數據庵楷,其他代碼不在詳述,無非就是轉換數據楣颠,最后還是要賦予AlertController
尽纽。
3.AlertController 源碼
在構造方法中獲得相對應的視圖。
這是之前介紹過的初始化實體內容的方法童漩,顯然是負責構建視圖的弄贿。
構建視圖的過程,通過獲得的數據構建相應的視圖內容矫膨。
所以說AlertController
是整個模式中負責組織建造的差凹,這也是Builder
模式的核心。
通過分析AlertDialog
的源碼侧馅,我們了解谷歌原生組件的Builder
的模式直奋,通過分層將邏輯簡化,代碼簡潔施禾。
Builder模式 實踐
根據以上脚线,我使用Builder模式重構了之前的小項目BottomPopUpDialog
。
public class BottomPopUpDialog extends DialogFragment {
private TextView mCancel;
private LinearLayout mContentLayout;
private Builder mBuilder;
private static BottomPopUpDialog getInstance(Builder builder) {
BottomPopUpDialog dialog = new BottomPopUpDialog();
dialog.mBuilder = builder;
return dialog;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//該方法需要放在onViewCreated比較合適, 若在 onStart 在部分機型(如:小米3)會出現閃爍的情況
getDialog().getWindow().setBackgroundDrawableResource(mBuilder.mBackgroundShadowColor);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Holo_Light_NoActionBar);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_pop_up_dialog, null);
initView(view);
registerListener(view);
setCancelable(true);
return view;
}
private void initView(View view) {
mContentLayout = (LinearLayout) view.findViewById(R.id.pop_dialog_content_layout);
mCancel = (TextView) view.findViewById(R.id.cancel);
initItemView();
}
private void registerListener(View view) {
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
dismiss();
}
return false;
}
});
mCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
@Override
public void show(FragmentManager manager, String tag) {
try {
super.show(manager, tag);
} catch (Exception e) {
e.printStackTrace();
}
}
private void initItemView() {
//循環(huán)添加item
for (int i = 0; i < mBuilder.mDataArray.length; i++) {
final PopupDialogItem dialogItem = new PopupDialogItem(getContext());
dialogItem.refreshData(mBuilder.mDataArray[i]);
//最后一項隱藏分割線
if (i == mBuilder.mDataArray.length - 1) {
dialogItem.hideLine();
}
//設置字體顏色
if (mBuilder.mColorArray.size() != 0 && mBuilder.mColorArray.get(i) != 0) {
dialogItem.setTextColor(mBuilder.mColorArray.get(i));
}
if (mBuilder.mLineColor != 0) {
dialogItem.setLineColor(mBuilder.mLineColor);
}
mContentLayout.addView(dialogItem);
dialogItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBuilder.mListener.onDialogClick(dialogItem.getItemContent());
if (mBuilder.mIsCallBackDismiss) dismiss();
}
});
}
}
public static class Builder {
private String[] mDataArray;
private SparseIntArray mColorArray = new SparseIntArray();
private BottomPopDialogOnClickListener mListener;
private int mLineColor;
private boolean mIsCallBackDismiss = false;
private int mBackgroundShadowColor = R.color.transparent_70;
/**
* 設置item數據
*/
public Builder setDialogData(String[] dataArray) {
mDataArray = dataArray;
return this;
}
/**
* 設置監(jiān)聽item監(jiān)聽器
*/
public Builder setItemOnListener(BottomPopDialogOnClickListener listener) {
mListener = listener;
return this;
}
/**
* 設置字體顏色
*
* @param index item的索引
* @param color res color
*/
public Builder setItemTextColor(int index, int color) {
mColorArray.put(index, color);
return this;
}
/**
* 設置item分隔線顏色
*/
public Builder setItemLineColor(int color) {
mLineColor = color;
return this;
}
/**
* 設置是否點擊回調取消dialog
*/
public Builder setCallBackDismiss(boolean dismiss) {
mIsCallBackDismiss = dismiss;
return this;
}
/**
* 設置dialog背景陰影顏色
*/
public Builder setBackgroundShadowColor(int color) {
mBackgroundShadowColor = color;
return this;
}
public BottomPopUpDialog create() {
return BottomPopUpDialog.getInstance(this);
}
public BottomPopUpDialog show(FragmentManager manager, String tag) {
BottomPopUpDialog dialog = create();
dialog.show(manager, tag);
return dialog;
}
}
public interface BottomPopDialogOnClickListener {
/**
* item點擊事件回調
*
* @param tag item字符串 用于識別item
*/
void onDialogClick(String tag);
}
}
這是我結合前面的Builder
模式寫的BottomPopUpDialog
弥搞。Buildr
模式是將一個對象的構建與顯示分離邮绿,將不同的參數一個一個添加進去渠旁,也是對于外部隱藏實現細節(jié),更是降低了耦合度船逮,方便以后的自由擴展顾腊。還有,我的實現省去了Controller
層代碼挖胃,我把控制層和UI層放在一起杂靶,這樣實現是為了簡單,我覺得Controller
層是在可以復用的場景下酱鸭,使用起來更有價值吗垮,而小組件可以更簡單的使用Builder
模式。編程是簡單實用凹髓。
重構之后的調用
new BottomPopUpDialog.Builder()
.setDialogData(getResources().getStringArray(R.array.popup_array))
.setItemTextColor(2, R.color.colorAccent)
.setItemTextColor(4, R.color.colorAccent)
.setCallBackDismiss(true)
.setItemLineColor(R.color.line_color)
.setItemOnListener(new BottomPopUpDialog.BottomPopDialogOnClickListener() {
@Override
public void onDialogClick(String tag) {
Snackbar.make(view, tag, Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
})
.show(getSupportFragmentManager(), "tag");
最后
這是一個簡單的編程模式烁登,記錄一下思路。