Android - изменить пользовательский вид заголовка во время выполнения - PullRequest
23 голосов
/ 04 мая 2009

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

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

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

Спасибо.

EDIT

Вот что я попробовал. Не обновляется даже при вызове 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();

Ответы [ 4 ]

31 голосов
/ 15 мая 2009

Проблема в том, что единственная реализация 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;)

EDIT

Как указано в комментариях, вышеупомянутый обходной путь не идеален. Вместо того, чтобы полагаться на константу 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);
13 голосов
/ 24 июня 2011

Правильный способ сделать это следующим образом:

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 () перед любым другим оператором, вы получите пустую строку заголовка, которая будет исправлена, но попытка найти идентификатор строки заголовка и удалить из нее все представления не будет.

0 голосов
/ 09 января 2010

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

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

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

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

0 голосов
/ 05 мая 2009

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

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

...