【问题标题】:Why Android is truncating my ActionBar title?为什么 Android 会截断我的 ActionBar 标题?
【发布时间】:2013-03-01 15:28:09
【问题描述】:

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

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

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

经过多次测试,当我在其中放入较小的文本时,Android 似乎正在缩小我的标题。但是当我放一个较长的文本时它并没有放大它,即使有足够的空间。

我能做些什么来解决这个问题?我想要一个比在短标题末尾添加空格更好的解决方案:)

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

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

【问题讨论】:

    标签: android android-actionbar


    【解决方案1】:

    我认为您对此无能为力。似乎操作栏标题的宽度相当有限,超过此范围的任何内容都会被截断。

    我想一种方法是显示:“My reqs (20)”而不是“My requests (20)”,但我明白这并不理想。

    【讨论】:

    • 嗨!感谢你的回复!非常感谢!只是一个问题:它是你已经遇到的吗?这是 ActionBar 的正常行为吗?还是我做错了什么?
    • 您好。这是我已经遇到的事情。我是一家大型全球报纸的 QA,我们的 android 开发人员也说这很正常......所以害怕看起来无法解决......除了我的建议或使用图像。尽管考虑到您的要求包括增加可能不够用的整数。
    • 嗯,这也是我在这个问题上几个小时后得出的结论。这很奇怪,因为有时标题会被截断,有时则不会。但是我没有找到一个简单的方法来解决这个问题......
    • 我知道...来自 iOS 它看起来确实很奇怪。尤其是当定位到横向时(当其他操作栏项目显示全文时),同一设备上允许的文本宽度有时会减小(而不是增加)。
    • Google 似乎有一个错误:使用 getActionBar().setTitle(title) 通过代码设置标题时,标题被随机截断!即使有地方!你有什么建议吗?
    【解决方案2】:

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

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

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

    请注意,当使用操作栏选项卡时,此解决方案将标题放置在横向模式下的选项卡右侧。

    【讨论】:

    • 谢谢!这个方案简单干净,我喜欢!
    【解决方案3】:

    我知道这个问题是很久以前发布的,但我最近遇到了这个问题,它引起了极大的头痛。我正在开发 Galaxy Note 10.1,我的标题是“BidItems”,而我只看到了动作溢出项,但有时,“BidItems”变成了“BidIt...”,这太荒谬了。经过大量测试,我发现我的应用程序中出现这种截断行为的原因是我正在使用我的一个片段中的((MyActivity) getApplication()).setTitle(); 方法调用一个方法。我的活动中的setTitle() 方法调用getActionBar().setTitle()。一旦我调用了这个方法,我的标题就被无缘无故地截断了。但只需从我的活动中调用 setTitle() 就可以了。

    我真的希望这能让人们免于它给我带来的头痛。

    【讨论】:

    • 我也一直遇到 setTitle() 的问题。我尝试将标题从片段签证界面更改为活动。但是如果不改变 textview 长度就无法做到这一点,这是一个转折点:只有在第一次启动时才会出现这个问题。我在第一次启动时运行 asynctask。也许这搞砸了。不知道。
    【解决方案4】:

    我要补充一点,你完全可以使用两行的操作栏标题来获得更多空间:

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

    【讨论】:

      【解决方案5】:

      您应该会发现我在这里发布的问题是likey问题,并且我也发布了解决方案。

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

      【讨论】:

        【解决方案6】:

        你的 AndroidManifest.xml 有你的活动定义,像这样

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

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

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

        【讨论】:

          【解决方案7】:

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

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

          ActionBar actionBar = getActivity().getActionBar();
          actionBar.setTitle(title);
          
          // for refreshing UI
          actionBar.setDisplayHomeAsUpEnabled(false);
          actionBar.setDisplayHomeAsUpEnabled(true);
          

          【讨论】:

          • 在经历了许多痛苦之后,您的解决方案是一个很好的线索,但对我不起作用,因为我并不总是想显示(或隐藏)“后退”按钮。我找到了一种更简单的刷新 UI 的方法:actionBar.setDisplayShowTitleEnabled(true); 在这种情况下,我们总是希望显示标题的机会更多:-)
          【解决方案8】:

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

          我发现将工具栏宽度从“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" />
          

          【讨论】:

            【解决方案9】:

            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

            【讨论】:

            • 这行得通。我正在使用 viewpager 并从我的标签片段之一中调用 setTitle。我不得不把它放在viewpager所在的父片段中并且错误消失了。
            【解决方案10】:

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

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

            事实证明这是真的。我发现只需覆盖活动的 setTitle 函数并将对 super 的调用包装在 postDelay 可运行文件中即可为我解决此问题:

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

            我使用工具栏的 postDelayed 作为一种方便的方法。但是您当然可以在这里使用处理程序。希望这会有所帮助。

            【讨论】:

            • 什么是“工具栏”?
            【解决方案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】:

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

              【讨论】:

                【解决方案13】:

                2013 年的一个问题,现在仍然存在。

                好吧,对于那些偶尔看到这种情况仍然感到震惊的人,即使您很高兴地使用 Androidx、所有最近的工件等。我找到了修复它的东西,它不需要自定义标题或任何特殊的东西。

                请记住,这可能不是你的情况,但它似乎在瞬间神奇地解决了这个问题。

                my 的情况下,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...(或在 LTR 语言中正确)使用 Ellipsize。

                但是,我注意到当我调用 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">
                
                

                它在预览中看起来不错,但它引起了我的注意,因为一个 _should not use match_parent in a child of 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"
                

                而这神奇地一劳永逸地解决了我被截断的标题。

                tl;博士

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-03-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-08-29
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多