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

StackOverflow https://stackoverflow.com/questions/820398

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

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

Спасибо.

Редактировать

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

Решение

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

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


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);

Другие советы

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

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

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

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

Только мои 2 цента:

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top