为什么Android会截断我的ActionBar标题?

时间:2013-03-13 15:33:42

标签: android android-actionbar

在我的应用程序中,我从显示的每个片段更改ActionBar中的标题。当我第一次启动我的应用程序时,我收到了一个请求列表,所以我的标题是“我的请求(20)”。

然后,当您单击该列表中的某个项目时,它正在替换我的Activity中的一个片段,并将标题设置为“Action”。

当我回到第一个视图(总是在同一个Activity中)时,我将标题重置为“我的请求(20)”,但是android决定截断它。结果就是“我的要求......”。

经过多次测试后,当我在其中放入较小的文字时,看起来Android正在缩小我的标题。但是,即使有足够的空间,当我放一个较长的文本时它也不会放大。

我该怎么做才能解决这个问题?我想要一个更好的解决方案,而不是在我的短标题末尾添加空格:)

以下是我用来更改ActionBar标题的代码:

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

13 个答案:

答案 0 :(得分:5)

我知道很久以前就已经发布了这个问题,但我最近遇到了这个问题,这让我很头疼。我正在制作Galaxy Note 10.1,我的标题是“BidItems”,我只看到了动作溢出项目,但有时候,“BidItems”变成了“BidIt ......”,这简直太荒谬了。经过大量测试后,我发现在我的应用程序中这种截断行为的原因是我从我的一个片段中使用((MyActivity) getApplication()).setTitle();方法调用了一个方法。我的Activity中的setTitle()方法调用getActionBar().setTitle()。我打电话给这个方法后,我的标题就被无缘无故截断了。但只是从我的活动中调用setTitle()就可以了。

我真的希望这可以让人们免受它给我带来的麻烦。

答案 1 :(得分:4)

我猜这个问题是通过刷新操作栏UI来解决的。

所以我用以下代码解决了。

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

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

答案 2 :(得分:4)

在我的特定情况下,我正在开发一个具有复杂本机菜单结构的混合应用程序。我从混合内容中调用深层链接时会间歇性地看到此问题,该内容将更新所选菜单选项并设置标题。

我尝试了几个建议的修复但没有运气。但设置一个自定义视图产生了一个奇怪的结果,让我觉得我正在处理竞争条件。

事实证明这是事实。我发现简单地覆盖了活动的setTitle函数,并在postDelay runnable中将调用包装到super中为我修复了这个问题:

xargs

我使用工具栏的postDelayed作为便捷方法。但你肯定可以在这里使用处理程序。希望这会有所帮助。

答案 3 :(得分:3)

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

参考:How to display android actionbar title without truncation occurring

答案 4 :(得分:2)

我使用in this post所述的自定义标题解决了这个问题。

这是我用来在标签更改时更改标题的代码

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

请注意,使用操作栏标签时,此解决方案会将标题置于横向模式的标签右侧。

答案 5 :(得分:2)

在我的情况下,文本被截断但没有省略号(...),最后一个字符总是被剪切,如下所示:

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" />

答案 6 :(得分:1)

我认为你无能为力。似乎是操作栏标题的宽度相当有限,而且任何内容都会被截断。

我想有一种方法可以显示:“我的要求(20)”而不是“我的要求(20)”,但我很欣赏这并不理想。

答案 7 :(得分:1)

我将补充说,您可以完全使用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);
    }

我在我的应用程序中使用它并且我很满意:)

归功于此post

答案 8 :(得分:1)

你应该发现我在这里发布的问题可能是问题,我也发布了解决方案。

Why my Android ActionBar doesn't update when it is explictily changed

答案 9 :(得分:1)

你的AndroidManifest.xml有你的活动定义

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

如果您将android:label="Whatever"更改为android:label=" "

它会起作用。我假设发生这种情况是因为android创建了一个TextView来显示标签,并且在调用setTitle时宽度不会重新调整大小。 因此,通过将初始标题设置为具有比您要设置标题更多的字符,它将不会被截断。

答案 10 :(得分:1)

因为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;
    }
}

抱歉我的英语不好。

答案 11 :(得分:0)

如果两年后仍然有人对正确答案感兴趣,我最近也遇到了这个问题,并且意识到原因是我从后台线程更新了标题。在Kotlin中使用supportActionBar?.title = <abc>
由于某种原因,该应用程序没有像通常那样崩溃,但有一个例外,其中提到您正在触摸UI线程之外的视图。相反,它设置新文本,但是跳过布局传递,从而导致包裹文本。
所以要么使用Activity.runOnUiThreadView.post,要么像我一样使用协程,使用withContext(Dispatchers.Main)触发更新标题的代码。

答案 12 :(得分:0)

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

这直接来自appCompat 1.1.0中最新的Toolbar.java(当前为2019年10月)。

没什么特别的,但是您可以看到,首次创建TitleTextView时,将其设置为singleLine并在END ...处使用Ellipsize(或LTR语言)。

但是,我注意到当我调用setTitle时,代码没有想到这一点,大概是因为titleTextView是在之前创建的(当时,使用Ellipsis设置为singleLine);当我调用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会怎样?”

我在Android Studio视觉编辑器的RelativeLayout中“右键单击”->转换为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">

它在预览中看起来不错,但是引起了我的注意,因为一个_不应在ConstraintLayout的子级中使用match_parent……所以……我将其更改为:

    <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"

这个神奇彻底解决了我被删节的标题。

tl; dr

从2019年起不再使用RelativeLayouts,从很多角度来看,它们都是不好的。如果工具栏包含在相对布局中,请考虑迁移到ConstraintLayout或任何其他ViewGroup。