Стиль AlertDialog setCustomTitle соответствует стандартному заголовку AlertDialog
Я работаю над приложением для Android, и у меня есть подкласс AlertDialog. Я хотел бы поместить 2 кнопки ImageButton справа от области заголовка диалогового окна (аналогично ActionBar в Activity). Для этого я использую setCustomTitle(), который заменяет область заголовка собственным представлением моего собственного творения. Это прекрасно работает, но стили моей настраиваемой области заголовка не совпадают со стандартным оформлением заголовка (высота, цвет, разделитель и т. Д.).
Мой вопрос: с пониманием того, что стилизация зависит от версии ОС и производителя, как я могу стилизовать свой пользовательский заголовок в диалоговом окне, чтобы он соответствовал стандартному стилю заголовка для других AlertDialogs?
Вот изображение an AlertDialog со стандартным стилем (это от ICS, но я хочу быть в состоянии соответствовать любому варианту - не этому конкретному стилю)
А вот изображение AlertDialog с пользовательским заголовком и кнопками (обратите внимание, что высота и цвет заголовка не соответствуют стандартному диалоговому окну)
РЕДАКТИРОВАТЬ: я не могу просто добавить ImageButtons к стандартному представлению заголовка, потому что у меня нет доступа к нему. Если вы знаете о (надежном, не взломанном) методе добавления кнопок в стандартную область заголовка, я бы тоже согласился с этим.
3 ответа
Учитывая, что в этом вопросе появился новый интерес, позвольте мне рассказать о том, как я "решил" это.
Во-первых, я использую http://actionbarsherlock.com/ в своем приложении. Я полагаю, что в этом нет необходимости, хотя это очень помогает, поскольку стили и темы, определенные в проекте ABS, позволяют мне подражать теме Holo на устройствах до ICS, что обеспечивает согласованное взаимодействие с приложением.
Во-вторых, мой "диалог" больше не является диалогом - это действие, тематически оформленное как диалог. Это делает манипулирование иерархией представления более простым, потому что у меня есть полный контроль. Поэтому добавление кнопок в область заголовка теперь тривиально.
Вот скриншоты (устройство 2.2 и эмулятор 4.1). Обратите внимание, что единственное существенное различие в стиле - это EditText, который я решил не учитывать.
Вот мой onCreate в моей диалоговой деятельности:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_tag);
setTitle(R.string.tag_dialog_title);
View sherlockTitle = findViewById(android.R.id.title);
if (sherlockTitle != null) {
sherlockTitle.setVisibility(View.GONE);
}
View sherlockDivider = findViewById(R.id.abs__titleDivider);
if (sherlockDivider != null) {
sherlockDivider.setVisibility(View.GONE);
}
// setup custom title area
final View titleArea = findViewById(R.id.dialog_custom_title_area);
if (titleArea != null) {
titleArea.setVisibility(View.VISIBLE);
TextView titleView = (TextView) titleArea.findViewById(R.id.custom_title);
if (titleView != null) {
titleView.setText(R.string.tag_dialog_title);
}
ImageButton cancelBtn = (ImageButton) titleArea.findViewById(R.id.cancel_btn);
cancelBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
cancelBtn.setVisibility(View.VISIBLE);
ImageButton okBtn = (ImageButton) titleArea.findViewById(R.id.ok_btn);
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// do stuff here
finish();
}
});
okBtn.setVisibility(View.VISIBLE);
}
}
А вот соответствующий макет для деятельности:
<LinearLayout
android:orientation="vertical"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
<LinearLayout
android:id="@+id/dialog_custom_title_area"
android:orientation="vertical"
android:fitsSystemWindows="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingRight="10dp">
<TextView
android:id="@+id/custom_title" style="?android:attr/windowTitleStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="@dimen/abs__alert_dialog_title_height"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:textColor="#ffffff"
android:gravity="center_vertical|left" />
<ImageButton
android:id="@+id/ok_btn"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:minWidth="@dimen/abs__action_button_min_width"
android:minHeight="@dimen/abs__alert_dialog_title_height"
android:scaleType="center"
android:src="@drawable/ic_action_accept"
android:background="@drawable/abs__item_background_holo_dark"
android:visibility="visible"
android:layout_gravity="center_vertical"
android:contentDescription="@string/acc_done"/>
<ImageButton
android:id="@+id/cancel_btn"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:minWidth="@dimen/abs__action_button_min_width"
android:minHeight="@dimen/abs__alert_dialog_title_height"
android:scaleType="center"
android:src="@drawable/ic_action_cancel"
android:background="@drawable/abs__item_background_holo_dark"
android:visibility="visible"
android:layout_gravity="center_vertical"
android:contentDescription="@string/acc_cancel"
/>
</LinearLayout>
<View
android:id="@+id/dialog_title_divider"
android:layout_width="fill_parent"
android:layout_height="2dip"
android:background="@color/abs__holo_blue_light" />
</LinearLayout>
<RelativeLayout
android:id="@+id/list_suggestions_layout"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<!-- this is where the main dialog area is laid out -->
</RelativeLayout>
</LinearLayout>
И, наконец, в моем AndroidManifext.xml вот как я определяю свою TagActivity:
<activity
android:icon="@drawable/ic_home"
android:name=".activity.TagActivity"
android:theme="@style/Theme.Sherlock.Dialog"/>
ОК, может быть, это не супер идеальное решение, и, возможно, это плохое решение, но я пробовал это на Android 2.3.7 и Android 4.1.2:
2.3.7 (real device)
4.1.2 (emulator)
Мы начнем с создания стиля заголовка диалога, чтобы убедиться, что у нас есть место для наших значков:
res/values/dialogstyles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Dialog" parent="@android:style/Theme.Dialog">
<item name="android:windowTitleStyle">@style/MyOwnDialogTitle</item>
</style>
<style name="MyOwnDialogTitle">
<!-- we need to make sure our images fit -->
<item name="android:layout_marginRight">100dp</item>
</style>
</resources>
res/values-v11/dialogstyles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Dialog" parent="@android:style/Theme.Holo.Dialog">
<item name="android:windowTitleStyle">@style/MyOwnDialogTitle</item>
</style>
</resources>
Затем мы создаем наш DialogFragment двумя хитростями:
установить стиль в
onCreate
:@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setStyle(DialogFragment.STYLE_NORMAL, R.style.Dialog); }
переопределение
onCreateView
и добавьте наш макет (кнопок) в диалог (см. комментарии)@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //we need the view to remove the tree observer (that's why it is final) final View view = inflater.inflate(R.layout.dialog_custom, container); getDialog().setTitle("Shush Dialog"); //register a layout listener to add our buttons view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @SuppressWarnings("deprecation") @SuppressLint("NewApi") @Override public void onGlobalLayout() { //inflate our buttons View menu = LayoutInflater.from(getActivity()).inflate(R.layout.layout_mymenu, null); //get the root view of the Dialog (I am pretty sure this is the weakest link) FrameLayout fl = ((FrameLayout) getDialog().getWindow().getDecorView()); //get the height of the root view (to estimate the height of the title) int height = fl.getHeight() - fl.getPaddingTop() - fl.getPaddingBottom(); //to estimate the height of the title, we subtract our view's height //we are sure we have the heights btw because layout is done height = height - view.getHeight(); //prepare the layout params for our view (this includes setting its width) //setting the height is not necessary if we ensure it is small //we could even add some padding but anyway! FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, height); params.gravity = Gravity.RIGHT | Gravity.TOP; //add the view and we are done fl.addView(menu, params); if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) view.getViewTreeObserver().removeOnGlobalLayoutListener(this); else view.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); return view; }
Хорошо, если это просто изображения, то вы просто должны убедиться, что все, что вы создаете в xml, масштабируется по пикселям плотности или DP для краткости. Самое простое кодирование, которое устанавливает рисование, обычно также задается пикселями и может потребоваться версия ручного кодирования для плотности пикселей.