Android通用UI元件之Dialog

Liberuman發表於2018-07-30

背景

Dialog是Android開發中常用的UI元件,為了方便顯示對話方塊,系統提供了AlertDialog,它提供了豐富的API,使用時只需要設定相應的屬性即可。但通常情況下,不會直接使用AlertDialog, 因為APP的設計並不一定都遵循Material Design的設計標準,同時這種通用的UI元件的設計風格也會經常發生變化。所以通常情況下,都會對AlertDialog的樣式進行自定義,使其能夠適用於各種設計風格。

自定義Dialog

自定義Dialog通常使用以下三種方式:

  • 通過AlertDialog提供的setView方法設定佈局;
  • 繼承AlertDialog, 在onCreate中呼叫setContentView載入佈局;
  • 繼承DialogFragment, 在onCreateView中載入佈局;

具體的核心程式碼實現如下所示:

// 方法一
View dialogView = View.inflate(this, R.layout.dialog_common_layout, null);
/**
 * 通過dialogView.findViewById獲取相應的View並設定對應的值
 */
new AlertDialog.Builder(this)
	.setView(dialogView)
	.show();


// 方法二
public class CommonDialog extends AlertDialog {

	public CommonDialog(Context context) {
		super(context);
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.dialog_common_layout);
		/**
		 * 通過findViewById獲取相應的View,設定對應的值
		 */
	}
}


// 方法三
public class CommonDialog extends DialogFragment {

	@Nullable
	@Override
	public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
		View dialogView = inflater.inflate(R.layout.dialog_common_layout, null);
		/**
		 * 通過dialogView.findViewById獲取相應的View並設定對應的值
		 */
		return dialogView;
	}
}
複製程式碼

第一種和第二種方法直接使用的Dialog型別, 這種方式Dialog的生命週期不好控制,容易出現WindowManager$BadTokenException異常。所以為了Dialog的生命週期能夠和Activity同步,推薦使用DialogFragment。但是在使用DialogFragment時,最好不要在onCreateView中直接載入佈局,因為這種方式相當於棄用了系統提供的AlertDialog樣式,如果APP要求使用系統提供的原生元件,此時修改起來可能就比較麻煩。其實DialogFragment還有一個重要的API——onCreateDialog,返回Dialog物件,所以可在裡面建立AlertDialog, 根據定義的樣式返回相應的風格。

APP中使用Dialog的地方很多,但常用的也就那麼幾種:提示對話方塊,選擇對話方塊,底部彈框,載入框,為了更好地進行風格切換,這裡同時支援了Material Design的設計風格(系統預設的樣式)和自定義的設計風格,只需要設定相應的風格即可。樣式如下圖所示,具體的原始碼參考CommonDilaog

image

修改Dialog預設樣式

在使用預設的對話方塊時,有時可能需要改變這幾個View的顏色,但AlertDialog並沒有提供直接的API進行設定,通過以下方法對其中的View進行設定。

AlertDialog Title的樣式可通過設定Dialog主題中的windowTitle屬性實現:

<!-- Title的文字樣式 -->
<style name="AlertDialogTitleStyle">
    <item name="android:textSize">48dp</item>
    <item name="android:textColor">#ff0000</item>
    <item name="android:textStyle">bold</item>
</style>

<!-- Dialog的主題樣式 -->
<style name="CommonDialog" parent="Theme.AppCompat.Dialog">
    <!-- 引用定義的Title樣式 -->
    <item name="android:windowTitleStyle">@style/AlertDialogTitleStyle</item>
    <item name="android:windowBackground">@color/transparent</item>
</style>
複製程式碼

其他的View可通過系統id進行獲取:

MessageViewId: android.R.id.message
PositiveButtonId: android.R.id.button1
NegativeButtonId: android.R.id.button2
複製程式碼

先呼叫Dialog的show方法(因為呼叫show方法後Dialog才開始載入佈局),然後獲取相應的View進行設定樣式,例如MessageView樣式的修改:

AlertDialog dialog = builder.show();
TextView messageText = dialog.findViewById(android.R.id.message);
messageText.setTextColor(Color.RED);
messageText.setTextSize(20);
複製程式碼

Dialog主題

在自定義Dialog時,可能需要對Dialog所使用的主題進行定義,這裡介紹Dialog主題中常用的幾個屬性:

<style name="CommonDialog" parent="Theme.AppCompat.Dialog">
    <!-- 背景遮罩的不透明度,backgroundDimEnabled為true時有效 -->
    <item name="android:backgroundDimAmount">0.4</item>
    <!-- 是否需要背景遮罩 -->
    <item name="android:backgroundDimEnabled">true</item>
    <!-- Dialog是否懸停 -->
    <item name="android:windowIsFloating">true</item>
    <!-- dialog的最小寬度佔總螢幕寬度的百分比 -->
    <item name="android:windowMinWidthMinor">85%</item>
    <!-- Dialog內容區域的背景 -->
    <item name="android:windowBackground">@color/transparent</item>
</style>
複製程式碼

windowBackground屬性需要注意一下,如果Dialog的自定義佈局中設定了背景,那麼這裡可將其設定為透明,否則在低版本的Android系統上會出現黑色邊框。如果自定義佈局中沒有設定背景,可將windowBackground屬性設定為相應的Drawable資源。

當然,Dialog的主題中還有很多屬性。但沒有對齊相關的屬性。如果需要修改Dialog的對齊方式,可在show方法呼叫之後,獲取Dialog的LayoutParams引數進行相應的設定。例如讓Dialog顯示在底部:

WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
params.gravity = Gravity.BOTTOM;
dialog.getWindow().setAttributes(params);
複製程式碼

總結

在對系統UI元件進行封裝時,一定要考慮原生的樣式,儘可能利用系統提供的元件實現。這樣可在各種不同的UI風格之間進行切換。

相關文章