場景:專案中某種原因 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 相關的屬性
再找 AlertDailog 過程中發現父類 Dailog 寫明瞭引用的 attr 名 嘗試直接引用 @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);
...
複製程式碼