Стиль AlertDialog setCustomTitle соответствует стандартному заголовку AlertDialog.

Я работаю над приложением для Android, и у меня есть подкласс AlertDialog. Я хотел бы поместить 2 кнопки изображения в правой части области заголовка диалогового окна (аналогично панели действий в действии). Для этого я использую setCustomTitle(), который заменяет область заголовка пользовательским представлением, созданным мной. Это отлично работает, но стиль моей пользовательской области заголовка отличается от стиля стандартного заголовка (высота, цвет, разделитель и т. д.).

Мой вопрос: принимая во внимание, что стиль зависит от версии ОС и производителя, как я могу оформить свой собственный заголовок в диалоговом окне, чтобы он соответствовал стандартному стилю заголовка для других диалоговых окон AlertDialog?

Вот изображение anAlertDialog со стандартным стилем (это из ICS, но я хочу иметь возможность сопоставить любой вариант, а не этот конкретный стиль) введите здесь описание изображения

А вот изображение AlertDialog с пользовательским заголовком и кнопками (обратите внимание, что высота и цвет заголовка не соответствуют стандартному диалогу) введите здесь описание изображения

РЕДАКТИРОВАТЬ: я не могу просто добавить ImageButtons в стандартный вид заголовка, потому что у меня нет к нему доступа. Если вы знаете (надежный, не взламывающий) метод добавления кнопок в стандартную область заголовка, я бы тоже его принял.


person mikejonesguy    schedule 25.05.2012    source источник


Ответы (3)


Учитывая, что к этому вопросу появился новый интерес, позвольте мне подробно рассказать о том, как я «решил» это.

Во-первых, я использую в своем приложении ActionBarSherlock. Я полагаю, в этом нет необходимости, хотя это очень помогает, потому что стили и темы, определенные в проекте ABS, позволяют мне имитировать тему Holo на устройствах до ICS, что обеспечивает единообразие работы в приложении.

Во-вторых, мой «диалог» больше не является диалогом — это деятельность, оформленная в виде диалога. Это упрощает манипулирование иерархией представлений, поскольку у меня есть полный контроль. Таким образом, добавление кнопок в область заголовка теперь тривиально.

Вот скриншоты (устройство 2.2 и эмулятор 4.1). Обратите внимание, что единственное существенное отличие стиля — это EditText, который я решил не затрагивать.

устройство 2.2Эмулятор 4.1

Вот мой 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"/>
person mikejonesguy    schedule 31.01.2013

Хорошо, может быть, это не идеальное решение, а может быть, это плохое решение, но я попробовал это на Android 2.3.7 и Android 4.1.2:

2.3.7 (real device)

2.3.7 (реальное устройство)

4.1.2 (emulator)

4.1.2 (эмулятор)


Начнем с создания стиля заголовка диалогового окна, чтобы убедиться, что у нас есть место для наших значков:

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;
    }
    
person Sherif elKhatib    schedule 30.01.2013

Хорошо, если это просто изображения, тогда вам просто нужно убедиться, что все, что вы создаете в xml, масштабируется по пикселям плотности или сокращенно DP. Наиболее простое кодирование, которое задает краску, обычно также задается пикселями, и может потребоваться ручная версия кодирования для плотности пикселей.

person sdfwer    schedule 25.05.2012
comment
Я думаю, вы неправильно поняли, что я ищу. Я добавил несколько ссылок на изображения для ясности. - person mikejonesguy; 25.05.2012
comment
Надеюсь, это ответы на ваш вопрос. - person sdfwer; 25.05.2012
comment
Нет, я думаю, вы все еще неправильно понимаете проблему. (См. мое последнее редактирование.) Область заголовка диалогового окна недоступна для меня по идентификатору, поэтому я не могу просто добавить в нее свои кнопки. Мне приходится использовать setCustomTitle(View view), который заменяет существующую область заголовка. - person mikejonesguy; 25.05.2012
comment
Я считаю, что это просто обертка содержимого для общего макета с несколькими вариантами масштабирования для нижнего вида. - person sdfwer; 25.05.2012