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

Почему Android урезает мой заголовок ActionBar?

В моем приложении я изменяю заголовок в ActionBar из каждого отображаемого фрагмента. Когда я впервые запускаю свои приложения, у меня есть список запросов, поэтому мой заголовок "Мои запросы (20)".

Затем, когда вы нажимаете на элемент в этом списке, он заменяет фрагмент в моей Activity и устанавливает заголовок в "Action".

Когда я вернусь к первому представлению (всегда в том же действии), я reset заголовок в "Мои запросы (20)", но андроид решил усечь его. Таким образом, результат "Мой запрос...".

После долгих испытаний, похоже, что Android сокращает мой заголовок, когда я помещаю в него меньший текст. Но он не увеличивает его, когда я помещаю более длинный текст, даже если есть много места.

Что я могу сделать, чтобы решить эту проблему? Я хотел бы получить лучшее решение, чем добавлять пробелы в конце моих коротких названий:)

Вот код, который я использую для изменения названия ActionBar:

getActivity().getActionBar().setTitle(title);   
4b9b3361

Ответ 1

Я решил эту проблему, используя пользовательское название, как описано в этом сообщении.

Это код, который я использую для изменения названия при изменении вкладки

((TextView) actionBar.getCustomView().findViewById(R.id.title)).setText(someTitle); 

Обратите внимание, что это решение помещает заголовок справа от вкладок в ландшафтном режиме при использовании вкладок в панели действий.

Ответ 2

Я знаю, что этот вопрос был опубликован давным-давно, но я недавно столкнулся с этой проблемой, и это вызвало ужасную головную боль. Я работаю над Galaxy Note 10.1, и мой заголовок был "BidItems", и я видел только элемент переполнения действия, но иногда "BidItems" стал "BidIt...", что просто смешно. После долгих испытаний я обнаружил, что причиной этого усекающего поведения в моем приложении является то, что я вызывал метод, используя метод ((MyActivity) getApplication()).setTitle(); из одного из моих фрагментов. Метод setTitle() в моей активности вызывает getActionBar().setTitle(). Как только я назвал этот метод, мой заголовок был усечен без причины. Но просто вызов setTitle() из моей активности работал нормально.

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

Ответ 3

Я предполагаю, что эта проблема решена обновлением пользовательского интерфейса панели действий.

Итак, я решил с помощью нижеприведенных кодов.

ActionBar actionBar = getActivity().getActionBar();
actionBar.setTitle(title);

// for refreshing UI
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);

Ответ 4

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

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

Это оказалось правдой. Я обнаружил, что просто переопределяя функцию setTitle и завершая вызов super в postDelay runnable, исправил это для меня:

@Override
public void setTitle(final CharSequence title) {
    toolBar.postDelayed(new Runnable() {
        @Override
        public void run() {
            MainActivity.super.setTitle(title);
        }
    }, 200);
}

Я использую панель инструментов postDelayed как метод удобства. Но вы можете, конечно, использовать обработчик здесь. Надеюсь, это поможет.

Ответ 5

put setTitle() в onCreateOptionsMenu помогает мне решить эту проблему.

В вашем фрагменте добавьте setHasOptionsMenu(true); в onCreateView(){}

Затем переопределите onCreateOptionsMenu().

Пример:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    // put getActivity in onCreateOptionsMenu will not return null
    if (getActivity() != null) {
        getActivity().setTitle(getResources().getString(R.string.Studies));
    }
}

Ссылка: Как отобразить заголовок панели управления Android без усечения

Ответ 6

В моем случае текст усекался, но не с эллипсисом (...), последний символ всегда был вырезан, например:

screenshot

Я узнал, что изменение ширины панели инструментов от "wrap_content" до "match_parent" решает проблему:

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_weight="1"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay" />

Ответ 7

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

Я думаю, что один из способов: отобразить: "Мои требования (20)", а не "Мои запросы (20)", но я понимаю, что это не идеальный вариант.

Ответ 8

Я добавлю, что вы можете полностью использовать заголовок панели действий на 2 строках, чтобы получить больше места:

//Set the title over 2 lines if needed:
    int titleId = Resources.getSystem()
            .getIdentifier("action_bar_title", "id", "android");
    if (titleId > 0) {
        TextView title = (TextView) findViewById(titleId);
        title.setSingleLine(false);
        title.setMaxLines(2);
        //          title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
    }

Я использую его в своем приложении, и я доволен им:)

Благодарим за сообщение

Ответ 10

В вашем AndroidManifest.xml есть определение активности, например:

<activity
        android:name="com.example.DetailsView"
        android:label="Details">
</activity>

Если вы измените android:label="Whatever" на android:label=" ",

Это сработает. Я предполагаю, что это происходит, потому что андроид создает TextView для отображения метки, а ширина не изменяет размер при вызове setTitle. Поэтому, задав начальное название, чтобы иметь больше символов, чем вы хотите установить заголовок, он не будет усечен.

Ответ 11

Поскольку ListView/GridView/RecyclerView одновременно называют notifyDataSetChanged(). По какой-то причине это приведет к обновлению макета, которое, как я думаю, приведет к хаосу обновления макета заголовка панели действий.

В принципе, вы можете postDelay() обновить заголовок, чтобы исправить эту проблему, но мне это не нравится.

Я решаю переопределить BaseAdapter.notifyDateSetChanged() и вручную просмотреть элемент представления. Он работает:

public abstract class BaseListAdapter<BEAN extends Unique, VH extends BaseListViewHolder<BEAN>> extends BaseAdapter {
    // data
    private List<BEAN> mList;
    // view holder
    private List<VH> mViewHolderList = new ArrayList<>();

    protected abstract void onBindViewHolder(VH holder, int position);

    protected abstract VH onCreateViewHolder(ViewGroup parent, int viewType);

    ...

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        VH viewHolder;
        if (convertView == null) {
            viewHolder = onCreateViewHolder(parent, getItemViewType(position));
            convertView = viewHolder.itemView;
            convertView.setTag(viewHolder);
            mViewHolderList.add(viewHolder);
        } else {
            //noinspection unchecked
            viewHolder = (VH) convertView.getTag();
        }

        viewHolder.setData(getItem(position));
        viewHolder.setPosition(position);
        onBindViewHolder(viewHolder, position);

        return convertView;
    }

    @Override
    public void notifyDataSetChanged() {
        if (mViewHolderList.size() == 0) {
            super.notifyDataSetChanged();
        } else {
            for (VH vh : mViewHolderList) {
                onBindViewHolder(vh, vh.getPosition());
            }
        }
    }

}

public class BaseListViewHolder<T> {
    public View itemView;
    private T data;

    private int position;

    public BaseListViewHolder(View itemView) {
        this.itemView = itemView;
    }

    @Override
    public T getData() {
        return data;
    }

    @Override
    public void setData(T data) {
        this.data = data;
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }
}

Извините за мой плохой английский.

Ответ 12

Если кто-то все еще заинтересован в правильном ответе более чем через 2 года, я недавно столкнулся с этой проблемой и понял, что причина в том, что я обновил заголовок из фоновой ветки. В Котлине используется supportActionBar?.title = <abc>.
По какой-то причине приложение не зависало, как обычно, за исключением того, что вы касаетесь представлений вне потока пользовательского интерфейса. Вместо этого он устанавливает новый текст, но пропускает проход макета, что приводит к переносу текста.
Поэтому либо используйте Activity.runOnUiThread или View.post, либо, когда используете сопрограммы, как я, используйте withContext(Dispatchers.Main), чтобы вызвать код, который обновляет заголовок ,

Ответ 13

Вопрос 2013 года, до сих пор не решенный вопрос.

Что ж, для тех, кто все еще шокирован, время от времени видят, что это происходит, даже если вы счастливо используете Androidx, все последние артефакты и т.д. Я нашел что-то, что исправило это и не требует пользовательских заголовков или чего-то особенного.

Имейте в виду, что это может быть не ваш случай, но, похоже, это волшебным образом решило эту проблему в одно мгновение.

В моем случае Toolbar был установлен как supportActionBar как обычно, и он содержался в CoordinatorLayout + AppBar. Сначала я собирался обвинить их, потому что почему бы и нет, но перед этим я решил проверить исходный код панели инструментов и отладить происходящее.

Я не мог сказать (но я достиг кода, который вызывал этот многоточие):

/**
 * Set the title of this toolbar.
 *
 * <p>A title should be used as the anchor for a section of content. It should
 * describe or name the content being viewed.</p>
 *
 * @param title Title to set
 */
public void setTitle(CharSequence title) {
    if (!TextUtils.isEmpty(title)) {
        if (mTitleTextView == null) {
            final Context context = getContext();
            mTitleTextView = new AppCompatTextView(context);
            mTitleTextView.setSingleLine();
            mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
            if (mTitleTextAppearance != 0) {
                mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
            }
            if (mTitleTextColor != null) {
                mTitleTextView.setTextColor(mTitleTextColor);
            }
        }
        if (!isChildOrHidden(mTitleTextView)) {
            addSystemView(mTitleTextView, true);
        }
    } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {
        removeView(mTitleTextView);
        mHiddenViews.remove(mTitleTextView);
    }
    if (mTitleTextView != null) {
        mTitleTextView.setText(title);
    }
    mTitleText = title;
}

Это прямо из последней версии Toolbar.java в appCompat 1.1.0 (последняя на данный момент в октябре 2019 г.).

Ничего особенного, но вы можете видеть, что, когда TitleTextView создается впервые, он устанавливается на singleLine и использует Ellipsize в END... (или прямо на языках LTR).

Тем не менее, я заметил, что когда я вызывал setTitle, код не пошел, думал, что, вероятно, потому что titleTextView был создан ранее (и в то время, установить на SingleLine с Ellipsis); когда я вызывал setTitle, весь код делал mTitleTextView.setText(title). Никакое количество invalidate(), forceLayout(), requestLayout() на панели инструментов не сможет это исправить.

После дальнейшей проверки я заметил, что мой макет (макет координатора) содержался в RelativeLayout.

Иерархия представлений выглядела так:

<RelativeLayout>
   <CoordinatorLayout>
       <AppBarLayout>
          <androidx.appcompat.widget.Toolbar />
       </AppBarLayout>
       <androidx.viewpager2.widget.ViewPager2 />
       <com.google.android.material.bottomnavigation.BottomNavigationView />
   </CoordinatorLayout>
</RelativeLayout>

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

Ради интереса я решил: "а что если я поменяю этот RelativeLayout на ConstraintLayout?"

Я "щелкнул правой кнопкой мыши" в RelativeLayout в визуальном редакторе Android Studio → преобразовать в ConstraintLayout, затем закончить (не трогал значения по умолчанию).

Теперь это выглядит так:

<ConstraintLayout>
   <CoordinatorLayout>
       <AppBarLayout>
          <androidx.appcompat.widget.Toolbar />
       </AppBarLayout>
       <androidx.viewpager2.widget.ViewPager2 />
       <com.google.android.material.bottomnavigation.BottomNavigationView />
   </CoordinatorLayout>
</ConstraintLayout>

То же самое, но ROOT больше не является относительным макетом.

Я сделал два ручных изменения в сгенерированном XML:

Вот как CoordinatorLayout выглядел после преобразования:

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent">

Это выглядело правильно в предварительном просмотре, но привлекло мое внимание, потому что один не должен использовать match_parent в потомке ConstraintLayout... так что... я изменил его на:

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/coordinatorLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

То же самое, что и раньше (макет координатора занимает весь экран).

Это благодаря новому ConstraintLayout, имеющему следующие данные:

    android:layout_width="match_parent"
    android:layout_height="match_parent"

И это волшебным образом решило мои усеченные названия раз и навсегда.

ТЛ; др

Не используйте RelativeLayouts больше в 2019 году, они плохие с многих точек зрения. Если ваша панель инструментов содержится в относительном макете, рассмотрите возможность перехода на ConstraintLayout или любую другую ViewGroup.