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

Jackson позволяет настраивать сторонние классы, используя функцию, называемую MixIn. Для дополнительной информации читайте:

  1. Джексон Миксин на помощь
  2. Джексон Mix-In аннотации

[1113 ] Вам нужно указать два новых интерфейса, которые позволят вам добавлять аннотации для других классов:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({@JsonSubTypes.Type(value = MySupplier.class, name = "MySupplier")})
interface SupplierAnnotations {
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
        @JsonSubTypes.Type(value = MyCalculator.class, name = "MyCalculator"),
        @JsonSubTypes.Type(value = HisCalculator.class, name = "HisCalculator") }
)
interface CalculatorAnnotations {
}

Теперь вы должны сообщить ObjectMapper о ваших новых классах. Вы можете сделать это следующим образом:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Calculator.class, CalculatorAnnotations.class);
mapper.addMixIn(Supplier.class, SupplierAnnotations.class);

Все, что вам нужно сделать, это перечислить подтипы для интерфейсов Suplier и Calculator.

23
задан curiousMind 14 December 2015 в 05:49
поделиться

4 ответа

Проблема в том, что единственная реализация 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);
31
ответ дан 29 November 2019 в 01:52
поделиться

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

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

13
ответ дан 29 November 2019 в 01:52
поделиться

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

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

0
ответ дан 29 November 2019 в 01:52
поделиться

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

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

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

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

0
ответ дан 29 November 2019 в 01:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: