跨系統 theme 呼叫私有的 style v1

keyboard3發表於2017-12-13

場景:專案中某種原因 Application 應用的主題是 android:Theme.Light ,而單獨某個頁面用的是 Theme.AppCompat 。 案例:主 A 頁面主題 Theme.Light , B 頁面主題 Theme.AppCompat 。現在兩處都會彈出 AlertDailog 框

未統一之前
一個應用彈出框兩套樣式肯定不行。 那麼我們該採取宣告方案解決呢? 前提條件:頁面 B 程式碼實現與 theme 主題強耦合 方案1:重寫頁面 B 改用 Theme.Light 主題 方案2:仿寫 Theme.Light 系統效果 方案3:頁面 B AlertDailog 採用 Theme.Light 的彈出框樣式 綜合考慮 方案1不僅工作量大而且還會破壞原始程式碼,可能會引入新問題。方案2新增工作量。方案3工作量小,可行性未知。

作為喜歡挑戰的程式設計師當然選擇方案3,我們來理清楚思路。 1.找到 Theme.Light 主題下 AlertDailog 引用的 style 2.在 AlertDailog.builder 建立的時候指定 style ( Theme )

進入 Theme.Light 查詢到與 AlertDialog 相關的屬性

跨系統 theme 呼叫私有的 style v1
再找 AlertDailog 過程中發現父類 Dailog 寫明瞭引用的 attr 名
跨系統 theme 呼叫私有的 style v1
嘗試直接引用 @style/Theme.Dialog.Alert 你會發現 as 會提示該資源非 public 無法被引用, 然後我去<sdk_path>\platforms\android-23\data\res\values\public.xml查詢這個屬性是否被宣告,搜尋確實沒有被宣告。 此時遇到了一個問題,我無法拿到 Theme.Light 下私有的 Theme.Dialog.Alert 資源 id 。

最終經過重重波折,想到了從 A 頁面獲取 theme 呼叫 resolveAttribute 解析出 Theme.Dialog.Alert 的資源 id ,然後放到靜態變數裡。當需要 AlertDailog 的時候就直接用這個解析出來的 Theme.Dialog.Alert 資源 id 。 注意前提是提前解析到這個資源 ID ,否則它解析失敗彈出的效果還是主題預設的 dialogTheme 效果。

主 A 頁面

public static int holoDialogThemeId=0;
....
 final TypedValue outValue = new TypedValue();
getTheme().resolveAttribute(android.R.attr.alertDialogTheme, outValue, true);
holoDialogThemeId = outValue.resourceId;
複製程式碼

彈出框使用

AlertDialog.Builder builder=new AlertDialog.Builder(context,holoDialogThemeId);
...
複製程式碼

相關文章