考拉Android統一彈框
作者:錢成傑
背景
在快速開發的背景下,經歷了n個版本後的考拉Android App中已經存在了各種各樣看似相同卻各有差別的彈框樣式。其中包括系統彈框和自定義彈框,並且在線上時常會出現IllegalArgumentException的異常,而現有的解決方法是通過工具類來保護呼叫show和dismiss方法,這種方式效率不高,而且覆蓋不全,開發過程中容易遺漏。另外現有的Builder方式的彈框構造工具雖然功能強大,能構造各種彈框,但是使用複雜,樣式邏輯耦合,使用成本太高。於是,便需要一款樣式統一、show和dismiss安全、呼叫簡單、構造方便的統一彈框工具。
目標
-
統一彈框的互動樣式
-
show和dismiss方法安全
-
樣式與邏輯解耦,使用者不必關心彈框樣式,只需要完成自己的續邏輯即可
-
使用簡單,一個介面即可獲得所需樣式
-
擴充套件性,可支援展示特別樣式彈框
怎麼做?
既然有了特定的目標,那麼就要開始彈框的設計了。彈框通過工廠模式設計生產,使用者通過CommonDialogFactory提供的介面,可以直接生產CommonDialog類、KaolaCommonDialog類、KaolaBottomCloseDialog類三種彈框,其中CommonDialog是為了相容舊邏輯保留的舊的彈框樣式,KaolaCommonDialog是新設計統一了樣式的彈框類,但是兩者在樣式上沒有很大的區別,KaolaBottomCloseDialog是一種底部關閉的彈框樣式。
0. 保留CommonDialog的舊的構建方式。
考慮到舊的彈框中有不少彈框的業務邏輯與舊的Builder工具樣式有耦合,為了保證業務邏輯不受影響,我保留了以前的Builder方式構造彈框的設計,並且對其進行了介面化封裝。這樣可以降低構造彈框的成本。
1. 整理目前專案中用到的彈框的樣式。
由於不熟悉別的模組中彈框到底有哪些樣式,所以需要整理目前專案中所有用到的彈框樣式。統計結果發現大部分彈框使用的是系統彈框,而自定義彈框中不少樣式已經不再使用,但是在舊的構造工具中依然存在,由於邏輯耦合,後期維護相對麻煩,這也驗證了我們統一彈框元件的必要性。
2. 慢慢從DialogManager裡面把樣式抽出來,形成基本樣式。
從舊的彈框管理類DialogManager中,將現在正在使用的彈框抽離出來,在彈框工廠CommonDialogFactory中封裝成單獨的介面以提供使用。也可以根據整理的介面,形成一套基本的彈框樣式,這樣在後面做樣式統一的時候就可以參考著現有的樣式去做了。
3. 具體彈框樣式形成文件維護在wiki上(提供使用幫助)。
那麼為了更方便地使用和維護統一彈框元件, ofollow,noindex" target="_blank">使用文件 是必不可少的。把現有的彈框樣式總結在wiki文件中,對於現有可用的彈框樣式也是一目瞭然;還可以根據文件中提供的案例進行呼叫開發,降低成本。
4. 樣式全部抽出來之後,那就按照統一的互動進行修正。
由於目前沒有視覺提供的統一樣式,所以我們基於第2點鐘抽離出來的基本樣式,按照這些樣式來做構建的統一。然後再按照後續設計提供的統一互動規範進行進一步的修正,慢慢做到樣式也統一,最後真正實現彈框的完全統一。
樣式
下圖中可以看到彈框類的繼承關係:
KaolaBaseDialog中實現了安全的show和dismiss方法:
@Overridepublic void show() {if (!checkAllow()) {return; }// 防止check無效 try {super.show(); } catch (Exception e) { e.printStackTrace(); } }@Overridepublic void dismiss() {if (mOnDismissListener != null) { mOnDismissListener.onDismiss(mDismissType); }if (!checkAllow()) {return; }try {super.dismiss(); } catch (Exception e) { e.printStackTrace(); } }/** * 檢查環境是否允許 * * @return */private boolean checkAllow() { Context context = this.getContext();if (context instanceof Lifeful) { Lifeful lifeful = (Lifeful) context;if (!lifeful.isAlive()) {return false; } } else if (context instanceof Activity) {if (!ActivityUtils.activityIsAlive(context)) {return false; } }return true; }
KaolaCommonDialog是通用樣式類:
KaolaBottomDialog是底部彈出浮層:
KaolaBottomConfirmDialog是底部確認浮層:
KaolaBottomCloseDialog是底部帶關閉彈框:
ExpectPickUpTimeDialog是時間選擇器浮層:
通用彈框的文案也支援SpannableString的多樣展示;另外可以看到KaolaBaseDialog可以使用在各種情況下,不僅僅是通用彈框,還可以是一些通用元件比如ExpectPickUpTimeDialog時間選擇器(不過這裡做成了與取件業務相關的元件)。
怎麼用?
KaolaCommonDialog的使用
直接呼叫CommonDialogFactory提供的createOneOrTwoButtonsCustomView介面,該介面可以提供標題、文案、自定義view、通用按鈕的展示,使用者可以通過wiki文件或者直接檢視介面註釋瞭解介面內容。
/** * 一個標題,一個文案,一個view,一個白底紅字negative(left)按鈕,一個紅底白字positive(right)按鈕 * * @param context * @param title 標題,傳空不帶標題 * @param message 提示文案 * @param view 自定義區域需要新增的view * @param leftBtn 左邊按鈕的內容(傳空不顯示按鈕) * @param rightBtn 右邊按鈕的內容(傳空不顯示按鈕) * @return KaolaCommonDialog */public KaolaCommonDialog createOneOrTwoButtonsWithCustomView(Context context, String title, CharSequence message, View view, String leftBtn, String rightBtn) { ... } KaolaCommonDialog dialog = CommonDialogFactory.getInstance() .createOneOrTwoButtonsWithCustomView(this, "標題", "提示文案", getCustomView(), "取消", "確定") .setOnLeftButtonClickListener(() -> ToastUtils.show("leftClick... negative")) .setOnRightButtonClickListener(() -> ToastUtils.show("rightClick... positive")) .setCancelableOutside(true); dialog.setOnDialogDismissListener(dismissType -> {// dismiss回撥 ThreadCore.getInstance().postOnMainLooper(new LifefulRunnable(new Runnable() {@Override public void run() {if (dismissType == KaolaBaseDialog.DISMISS_TYPE_POSITIVE) { ToastUtils.show("右側按鈕點選消失"); } else if (dismissType == KaolaBaseDialog.DISMISS_TYPE_NEGATIVE) { ToastUtils.show("左側按鈕點選消失"); } else { ToastUtils.show("其他消失"); } } }, DialogTestActivity.this), 1000); });// 不展示頂部分割線dialog.dividerTop.setVisibility(View.GONE); dialog.show();
考慮到一些特殊情況的需求,預設的樣式無法滿足視覺要求的時候,就需要定製化一些彈框中的內容了。所以彈框類中的各個成員以public的形式開發給使用者,以適應各種定製化要求,比如:不希望展示title下面的分割線,可以直接獲取dividerTop物件進行設定。另外自定義view引數可以滿足對彈框內容的特殊化定製。在統一了彈框呼叫之後,依然具有很強的擴充套件性。
KaolaBottomDialog的使用
考慮到底部浮層的多樣性,沒有將KaolaBottomDialog的構建放入CommonDialogFactory中,而是使用通用的構建方式構建。
private KaolaBottomDialog chooseDialog; ... chooseDialog = new KaolaBottomDialog(this);// 展示浮層右上角關閉按鈕chooseDialog.showRightClose(true); ...// 設定標題(String)和內容(ListView)chooseDialog.setContent(getString(R.string.refund_delivery), dialogListView)// 限制浮層最大屏高比(最大為螢幕高度的2/3) .setDialogHeight(2f / 3); chooseDialog.show();
思考
統一互動既能夠給產品帶來更好體驗,又可以減少開發者不必要的開發工作,降低程式碼耦合,提高工作效率,是一個建議並值得去做的事情。目前的統一彈框方案還是有很多不足,等著我們去優化,比如將所有Dialog統一到CommonDialogFactory中去構建,再使用等等。
網易雲產品 免費體驗館 ,無套路試用,零成本體驗雲端計算價值。
本文來自網易實踐者社群,經作者錢成傑授權釋出
更多網易研發、產品、運營經驗分享請訪問 網易雲社群 。
相關文章:
【推薦】 如何做好iOS應用安全?這有一把行之有效的“三板斧”
【推薦】 微服務監控探索