Tôi thấy rằng kiểu dáng là về cách khóa theo cách của bạn thông qua khung. những gì (hầu như luôn luôn) xuất phát từ việc triển khai tiện ích con. nơi, tôi thấy là tất cả các nơi. Tôi sẽ cố gắng hết sức để giải thích quy trình thông qua trường hợp sử dụng cụ thể của bạn - nút của AlertDialog.
Bắt đầu tắt:
Bạn đã có này đã tìm ra: chúng ta bắt đầu với mã nguồn của widget. Chúng tôi đặc biệt cố gắng tìm - nơi các nút AlertDialog nhận được màu văn bản của họ. Vì vậy, chúng tôi bắt đầu bằng cách xem các nút này đến từ đâu. Chúng có được tạo ra một cách rõ ràng trong thời gian chạy không? Hoặc chúng được định nghĩa trong bố cục xml, đang được tăng cao?
Trong mã nguồn, chúng tôi thấy rằng mAlert
xử lý các tùy chọn nút trong số những thứ khác:
public void setButton(int whichButton, CharSequence text, Message msg) {
mAlert.setButton(whichButton, text, null, msg);
}
mAlert
là một thể hiện của AlertController
. Trong constructor của nó, chúng ta thấy rằng thuộc tính alertDialogStyle
xác định bố cục xml:
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.AlertDialog,
com.android.internal.R.attr.alertDialogStyle, 0);
mAlertDialogLayout =
a.getResourceId(
com.android.internal.R.styleable.AlertDialog_layout,
com.android.internal.R.layout.alert_dialog);
Vì vậy, cách bố trí chúng ta nên nhìn vào là alert_dialog.xml
-[sdk_folder]/platforms/android-21/data/res/layout/alert_dialog.xml
:
Cách bố trí xml là khá dài. Đây là phần có liên quan:
<LinearLayout>
....
....
<LinearLayout android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical" >
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="4dip"
android:paddingStart="2dip"
android:paddingEnd="2dip"
android:measureWithLargestChild="true">
<LinearLayout android:id="@+id/leftSpacer"
android:layout_weight="0.25"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
<Button android:id="@+id/button1"
android:layout_width="0dip"
android:layout_gravity="start"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button3"
android:layout_width="0dip"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="end"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
android:layout_width="0dip"
android:layout_weight="0.25"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
</LinearLayout>
Bây giờ chúng ta biết rằng các nút có được phong cách tổ chức bởi thuộc tính buttonBarButtonStyle
.
Head qua [sdk_folder]/platforms/android-21/data/res/values/themes.material.xml
và tìm kiếm buttonBarButtonStyle
:
<!-- Defined under `<style name="Theme.Material">` -->
<item name="buttonBarButtonStyle">@style/Widget.Material.Button.ButtonBar.AlertDialog</item>
<!-- Defined under `<style name="Theme.Material.Light">` -->
<item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.ButtonBar.AlertDialog</item>
Tùy thuộc vào những gì chủ đề của cha mẹ hoạt động của bạn là, buttonBarButtonStyle
sẽ đề cập đến một trong hai phong cách này. Bây giờ, hãy giả sử chủ đề hoạt động của bạn mở rộng Theme.Material
.Chúng tôi sẽ xem xét @style/Widget.Material.Button.ButtonBar.AlertDialog
:
mở [sdk_folder]/platforms/android-21/data/res/values/styles_material.xml
và tìm kiếm Widget.Material.Button.ButtonBar.AlertDialog
:
<!-- Alert dialog button bar button -->
<style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Colored">
<item name="minWidth">64dp</item>
<item name="maxLines">2</item>
<item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
Được rồi. Nhưng những giá trị này không giúp chúng ta xác định màu chữ của nút. Chúng ta nên nhìn vào phong cách cha mẹ tiếp theo - Widget.Material.Button.Borderless.Colored
:
<!-- Colored borderless ink button -->
<style name="Widget.Material.Button.Borderless.Colored">
<item name="textColor">?attr/colorAccent</item>
<item name="stateListAnimator">@anim/disabled_anim_material</item>
</style>
Cuối cùng, chúng tôi tìm ra textColor
- và cung cấp của mình bằng attr/colorAccent
khởi tạo trong Theme.Material
:
<item name="colorAccent">@color/accent_material_dark</item>
Đối Theme.Material.Light
, colorAccent
được định nghĩa là:
<item name="colorAccent">@color/accent_material_light</item>
Duyệt đến [sdk_folder]/platforms/android-21/data/res/values/colors_material.xml
và định vị thứ màu sắc ese:
<color name="accent_material_dark">@color/material_deep_teal_200</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>
<color name="material_deep_teal_200">#ff80cbc4</color>
<color name="material_deep_teal_500">#ff009688</color>
Ảnh chụp màn hình của một AlertDialog và văn bản màu tương ứng:
Shortcut:
Đôi khi, nó dễ dàng hơn để đọc các giá trị màu (như trong hình trên) và tìm kiếm bằng cách sử dụng AndroidXRef. Cách tiếp cận này sẽ không hữu ích trong trường hợp của bạn vì #80cbc4
sẽ chỉ chỉ ra rằng màu nhấn của nó. Bạn vẫn sẽ phải xác định vị trí Widget.Material.Button.Borderless.Colored
và buộc nó với thuộc tính buttonBarButtonStyle
.
Thay đổi nút của văn bản màu:
Lý tưởng nhất, chúng ta nên tạo ra một phong cách mà kéo dài Widget.Material.Button.ButtonBar.AlertDialog
, ghi đè android:textColor
bên trong nó, và gán nó vào thuộc tính buttonBarButtonStyle
. Nhưng, điều này sẽ không hoạt động - dự án của bạn sẽ không biên dịch. Điều này là do Widget.Material.Button.ButtonBar.AlertDialog
là kiểu không công khai và do đó không thể mở rộng. Bạn có thể xác nhận điều này bằng cách kiểm tra Link.
Chúng tôi sẽ làm điều tốt nhất tiếp theo - mở rộng phong cách mẹ của Widget.Material.Button.ButtonBar.AlertDialog
-Widget.Material.Button.Borderless.Colored
mà là công khai.
<style name="CusButtonBarButtonStyle"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
<!-- Yellow -->
<item name="android:textColor">#ffffff00</item>
<!-- From Widget.Material.Button.ButtonBar.AlertDialog -->
<item name="android:minWidth">64dp</item>
<item name="android:maxLines">2</item>
<item name="android:minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
Lưu ý rằng chúng tôi thêm 3 mục sau khi ghi đè android:textColor
. Đây là từ phong cách ngoài công lập Widget.Material.Button.ButtonBar.AlertDialog
. Vì chúng ta không thể mở rộng nó trực tiếp, chúng ta phải bao gồm các mục mà nó định nghĩa. Lưu ý: Giá trị dimen sẽ phải được tra cứu và chuyển đến res/values(-xxxxx)/dimens.xml
tệp phù hợp trong dự án của bạn.
Kiểu CusButtonBarButtonStyle
sẽ được gán cho thuộc tính buttonBarButtonStyle
. Nhưng câu hỏi đặt ra là, một AlertDialog sẽ biết điều này như thế nào?Từ mã nguồn:
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
Đi qua 0
như là đối số thứ hai cho resolveDialogTheme(Context, int)
sẽ kết thúc trong mệnh đề else
:
static int resolveDialogTheme(Context context, int resid) {
if (resid == THEME_TRADITIONAL) {
....
} else {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(
com.android.internal.R.attr.alertDialogTheme,
outValue, true);
return outValue.resourceId;
}
}
Chúng tôi bây giờ biết rằng chủ đề được tổ chức bởi alertDialogTheme
thuộc tính. Tiếp theo, chúng tôi xem xét những gì alertDialogTheme
trỏ tới. Giá trị của thuộc tính này sẽ phụ thuộc vào chủ đề gốc của hoạt động của bạn. Duyệt đến thư mục sdk của bạn và tìm số values/themes_material.xml
bên trong android-21. Tìm kiếm alertDialogTheme
. Kết quả:
<!-- Defined under `<style name="Theme.Material">` -->
<item name="alertDialogTheme">@style/Theme.Material.Dialog.Alert</item>
<!-- Defined under `<style name="Theme.Material.Light">` -->
<item name="alertDialogTheme">@style/Theme.Material.Light.Dialog.Alert</item>
<!-- Defined under `<style name="Theme.Material.Settings">` -->
<item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
Vì vậy, dựa trên chủ đề cơ bản của hoạt động, alertDialogTheme
sẽ giữ một trong 3 giá trị này. Để cho AlertDialog biết về CusButtonBarButtonStyle
, chúng tôi cần ghi đè thuộc tính alertDialogTheme
trong chủ đề của ứng dụng. Giả sử, chúng tôi đang sử dụng Theme.Material
làm chủ đề cơ sở.
<style name="AppTheme" parent="android:Theme.Material">
<item name="android:alertDialogTheme">@style/CusAlertDialogTheme</item>
</style>
Từ trên, chúng ta biết rằng alertDialogTheme
điểm để Theme.Material.Dialog.Alert
khi chủ đề cơ bản của ứng dụng của bạn là Theme.Material
. Vì vậy, nên có CusAlertDialogTheme
Theme.Material.Dialog.Alert
như mẹ của nó:
<style name="CusAlertDialogTheme"
parent="android:Theme.Material.Dialog.Alert">
<item name="android:buttonBarButtonStyle">@style/CusButtonBarButtonStyle</item>
</style>
Kết quả:
Vì vậy, thay vì chấp nhận cá để ăn, có thể giúp bạn dạy tôi cá để thay thế?
Ít nhất, tôi hy vọng đã giải thích được cá ở đâu.
P.S. Tôi nhận ra tôi đã đăng một con voi ma mút.
WOW, chỉ WOW. Đó là mớ hỗn độn mà tôi tưởng tượng ra. Google vẫn cần phải tìm hiểu nhiều về phát triển API: (Ít nhất Material cần cố gắng khắc phục những vấn đề này. Bây giờ, để xem liệu tôi có thể dịch những gì tôi đã học được ở đây sang chủ đề Appcompat mà tôi đang thực sự sử dụng hay không) – velis
@velis lol, Hãy cho tôi biết nếu bạn có thể sử dụng phương pháp này trong việc tùy chỉnh chủ đề Appcompat.Nếu bạn đâm vào tường, chúng ta có thể thảo luận thêm. Nhân tiện, câu hỏi hay, và cảm ơn vì tiền thưởng. – Vikram
trên android-24 tệp chủ đề là themes_material.xml – dazza5000