Подтвердить что ты не робот

Android - изменение пользовательского заголовка во время выполнения

Я использую собственный заголовок в своем приложении для каждого действия. В одном из действий, основанном на нажатиях кнопок, мне нужно изменить пользовательский вид заголовка. Теперь это прекрасно работает при каждом вызове setFeatureInt.

Но если я попытаюсь обновить какие-либо элементы в настраиваемом заголовке (например, измените текст кнопки или текстовое представление заголовка), обновление не произойдет.

Отладка через код показывает, что текстовые представления и экземпляры кнопок не равны нулю, и я также могу видеть пользовательскую строку заголовка. Но текст в текстовом представлении или кнопке не обновляется. Кто-нибудь еще столкнулся с этой проблемой? Как его разрешить?

Спасибо.

ИЗМЕНИТЬ

Вот что я пробовал. Не обновляется даже при вызове postInvalidate.

    getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.text_title);

    TextView databar = (TextView) findViewById(R.id.title_text);
    databar.setText("Some Text");
    databar.postInvalidate();

    Button leftButton = (Button) findViewById(R.id.left_btn);
    leftButton.setOnClickListener(mLeftListener);
    leftButton.setText("Left Btn");
    leftButton.postInvalidate();

    Button rightBtn = (Button) findViewById(R.id.right_btn);
    rightBtn.setOnClickListener(mRightListener);
    rightBtn.postInvalidate();
4b9b3361

Ответ 1

Проблема в том, что единственная Window реализация (PhoneWindow) использует LayoutInflater в своем методе setFeatureInt и создает новый макет с inflate и attachToRoot=true. Следовательно, когда вы вызываете setFeatureInt, новые макеты не заменяются, а прикрепляются к внутреннему контейнеру заголовка и, таким образом, нарисованы друг над другом.

Вы можете обойти это, используя следующий вспомогательный метод вместо setFeatureInt. Помощник просто удаляет все представления из внутреннего контейнера заголовка перед установкой новой настраиваемой функции заголовка:


private void setCustomTitleFeatureInt(int value) {
    try {
        // retrieve value for com.android.internal.R.id.title_container(=0x1020149)
        int titleContainerId = (Integer) Class.forName(
            "com.android.internal.R$id").getField("title_container").get(null);

        // remove all views from titleContainer
        ((ViewGroup) getWindow().findViewById(titleContainerId)).removeAllViews();

        // add new custom title view 
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, value);

    } catch(Exception ex) {
        // whatever you want to do here..
    }
}

Я не уверен, предназначено ли текущее поведение setFeatureInt, но оно, конечно, не документировано так или иначе, поэтому я возьму это для разработчиков Android.)

ИЗМЕНИТЬ

Как отмечено в комментариях, вышеупомянутое обходное решение не является идеальным. Вместо того, чтобы полагаться на константу com.android.internal.R.id.title_container, вы могли бы просто скрыть старый пользовательский заголовок всякий раз, когда вы установите новый.

Предположим, что у вас есть два настраиваемых макета заголовка:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/custom_title_1" ...

и

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/custom_title_2" ...

и вы хотите заменить custom_title_1 на custom_title_2, вы можете скрыть прежнее и использовать setFeatureInt, чтобы добавить последнее:

findViewById(R.id.custom_title_1).setVisibility(View.GONE);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_2);

Ответ 2

Правильный способ сделать это:

requestWindowFeature( Window.FEATURE_CUSTOM_TITLE );
setContentView( R.layout.my_layout );
getWindow().setFeatureInt( Window.FEATURE_CUSTOM_TITLE, R.layout.my_custom_title );
super.onCreate( savedInstanceState );

Обратите внимание, что порядок этих утверждений очень важен.

Если вы вызываете super.onCreate() перед любым из других утверждений, вы получите пустую строку заголовка, в которой взломать идентификатор заголовка и удаление всех его представлений будет исправлена, но не рекомендуется.

Ответ 3

Вы вызываете invalidate или postInvalidate для перерисовки представления после обновления текста? Если это пользовательский вид, можете ли вы поставить точку останова в код рисования, чтобы убедиться, что он вызван?

Если вы используете поток пользовательского интерфейса, вы можете вызвать "invalidate", если вы этого не сделали, вы должны называть "postInvalidate" или представление не будет перерисовываться.

Ответ 4

Просто мой 2c стоит:

При работе в MapActivity, запрашивая собственное название, в результате не отображается ни один заголовок.

К счастью, все, что я хотел сделать, это установить текст заголовка по-разному, и я скоро понял, что просто вызов setTitle() внутри onCreate() работал у меня (я назвал его после вызова setContentView())

Извините, но у меня нет времени прямо сейчас, чтобы отладить это и выяснить, почему то, что я делаю, не работает, и почему его изменение заставило его работать. Как я уже сказал, просто подумал, что это может помочь кому-то по дороге.