Android Lollipop,AppCompat ActionBar自定义视图不能占用整个屏幕宽度。

97

所以,我刚刚将我的代码库更新为Lollipop版本,但现在在使用Action Bar时遇到了问题。我正在使用AppCompat和ActionBarActivity,并填充自定义视图。似乎自定义视图不再占据整个屏幕的宽度,左侧留下一个薄条。

Building with 19 之前的样子

Building with 21 现在的样子

以下是我用来设置Action Bar的代码。有没有人有任何想法?

final ActionBar actionBar = getSupportActionBar();
if(actionBar != null) {
    actionBar.setDisplayHomeAsUpEnabled(false);
    actionBar.setDisplayShowHomeEnabled(false);
    actionBar.setDisplayShowTitleEnabled(false);
    actionBar.setDisplayShowCustomEnabled(true);
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    actionBar.setCustomView(R.layout.action_bar_content_search_custom_view);
    actionBar.setBackgroundDrawable(null);
    // actionBar.setStackedBackgroundDrawable(null);
    TextView title = (TextView) actionBar.getCustomView().findViewById(R.id.action_bar_title);
    title.setText(R.string.youtube);
    ImageView back = (ImageView) actionBar.getCustomView().findViewById(R.id.action_bar_back);
    back.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            finish();
        }
    });
}

编辑

移除自定义视图并更改背景后,现在占据了整个宽度。那么问题是,我们如何使CustomView占据ActionBar的整个宽度?


你可以在层次结构视图中查看你的活动,无论是否使用自定义视图,并查看是否能够确定由于自定义视图而导致布局规则发生了什么变化。这可能是新的 appcompat-v7 中的一个错误。 - CommonsWare
看起来这个地方是为 ImageView 预留的。试试先把它禁用看看。 - Nikola Despotoski
1
你好,看起来这是一个很好的解决方案,可以让自定义视图占据整个宽度。我曾经遇到过即使设置了布局权重也无法扩展的问题。请参阅此处:http://stackoverflow.com/a/20794736/581574 - ratana
@StevieKideckel 你是如何解决你的问题的?我也遇到了同样的问题,是在API级别21中的ActionBar。 - Erum
你尝试过被选中的答案吗?它对我有效。 - Stevie Kideckel
显示剩余3条评论
9个回答

111
看起来这是由于最近的appcompat-v7更新中对ActionBar进行的最新更改引起的。似乎有很大的变化需要你处理操作栏。
我遇到了同样的问题,阅读ActionBar文档,特别是以下引用后,我找到了解决方案。
引用如下:
从Android L(API级别21)开始,应用程序布局中的任何工具栏小部件都可以表示操作栏。应用程序可以向Activity发出信号,指示哪个工具栏应被视为Activity的操作栏。使用此功能的活动应使用提供的一个.NoActionBar主题之一,将windowActionBar属性设置为false或以其他方式不请求窗口特性。
在我看来,AppCompat主题已经更改,在一方面似乎破坏了一些东西,但在另一方面提供了更多的灵活性。我建议按照以下步骤操作:
1. 在你的活动中使用 .NoActionBar风格,如上述引用所述。 2. 将android.support.v7.widget.Toolbar添加到你的Activity布局中。 3. 设置app:contentInsetStart="0dp"属性。这是你在问题描述中提到的边距的主要问题
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/actionBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:contentInsetEnd="0dp"
    app:contentInsetStart="0dp" >
</android.support.v7.widget.Toolbar>

通常建议您在单独的布局文件中执行此操作,并在活动布局中使用include,这样如果在多个活动中使用,则只需要在一个地方自定义工具栏。
<include layout="@layout/view_action_bar" />
  1. 在你的Activity的onCreate方法中使用findViewByIdsetSupportActionBar告诉Activity哪个Toolbar应该被视为Activity的操作栏
Toolbar actionBar = (Toolbar) findViewById(R.id.actionBar);
setSupportActionBar(actionBar);
  1. 一旦你这样做了,所有在 onCreateOptionsMenu 中添加的操作都将添加到工具栏中,并且它将被视为活动操作栏。
  2. 进一步按需自定义工具栏(添加子视图等)。

1
我正在尝试在导航抽屉中使用工具栏,但是我遇到了“错误膨胀类片段”的错误。 - Ahmed Nawaz
9
在命名空间声明中,不应使用显式包名称。请使用 xmlns:app="http://schemas.android.com/apk/res-auto" - Liminal
1
不需要使用 setCustomView。只需构建一个包含您想要包含在工具栏中的小部件的布局文件(例如,在答案第3节中描述的布局文件中添加子视图)。 - Muzikant
我在工具栏中添加了以下内容: app:contentInsetEnd="0dp" app:contentInsetStart="0dp", 现在它能正常工作了! - void
只有在扩展AppCompatActivity时才能使用此方法,因为在常规的Activity中无法使用setSupportActionBar(ToolBar)。是否有任何解决方法,而不必使用AppCompatActivity - h_k
显示剩余9条评论

51

不要像Muzikant提到的那样这个答案一样做太多的工作。

    getSupportActionBar().setDisplayShowHomeEnabled(false);
    getSupportActionBar().setDisplayShowTitleEnabled(false);
    getSupportActionBar().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
    LayoutInflater mInflater = LayoutInflater.from(this);

    View mCustomView = mInflater.inflate(R.layout.action_bar_home, null);
    getSupportActionBar().setCustomView(mCustomView);
    getSupportActionBar().setDisplayShowCustomEnabled(true);
    Toolbar parent =(Toolbar) mCustomView.getParent();//first get parent toolbar of current action bar 
    parent.setContentInsetsAbsolute(0,0);// set padding programmatically to 0dp

为解决你的问题,你只需添加最后两行代码。

希望这可以帮助你和其他人。

更新:经过一些研究,我发现这种解决方法在某些情况下不起作用。左侧间隙(主页或返回)将被删除,但右侧间隙(菜单)将保持原样。以下是这些情况下的解决方案。

View v = getSupportActionBar().getCustomView();
LayoutParams lp = v.getLayoutParams();
lp.width = LayoutParams.MATCH_PARENT;
v.setLayoutParams(lp);
请将以下四行代码添加到上面的代码,以便支持操作栏右侧的间隙也被移除。

谢谢!谢谢!最后两行是我一直在寻找的! - digitalmidges
这些行应该添加在哪里?在工具栏部分之后吗? - Zen
1
@summers 是的,在工具栏代码之后立即添加它们。 - Amrut Bidri

31

我认为你也可以在样式中实现这个。试试这个。我在KitKat上测试过了。

<style name="AppTheme" parent="Theme.AppCompat">
  <item name="toolbarStyle">@style/AppThemeToolbar</item>
</style>

<style name="AppThemeToolbar" parent="Widget.AppCompat.Toolbar" >
  <item name="contentInsetStart">0dp</item>
</style>

1
这个答案是错误的:android:contentInsetStart 需要 API 级别 21(当前最低级别为 14) - SBotirov
这确实有效!使用最新版本的支持库,我认为您不需要两次声明属性(android:属性不是必需的)。 - BoD
我一直在寻找这个问题的答案,当我发现你的回答时,我发现我已经点赞了!所以谢谢两次。 - user1732313
适用于我..谢谢 - Bala Vishnu
对我没有起作用,仍然有左/右填充。 - Justin
显示剩余2条评论

8

其他答案对我都不起作用,所以我查看了实际的AppCompat v7样式,可以在这里找到。

如果你查看Base.Widget.AppCompat.ActionBar样式,它包含:

<item name="contentInsetStart">@dimen/abc_action_bar_content_inset_material</item>
<item name="contentInsetEnd">@dimen/abc_action_bar_content_inset_material</item>

很显然,我们只需要在自己的操作栏样式中覆盖这些属性:

<style name="ActionBar" parent="@style/Base.Widget.AppCompat.ActionBar">
        <item name="contentInsetStart">0dp</item>
        <item name="contentInsetEnd">0dp</item>
</style>

这对我非常有帮助,希望它也能帮助其他人。


是的,正如所选答案所述,关键在于ActionBar/Toolbar的contentInsetStart和contentInsetEnd属性。定义自己的样式是有效的,但您也可以在xml中将它们设置为0dp的Toolbar属性。 - Stevie Kideckel

1
在反复尝试后,我终于找到了解决方法。
 Toolbar toolbar = (Toolbar) actionBar.getCustomView().getParent();
        toolbar.setContentInsetStartWithNavigation(0);
        toolbar.setContentInsetEndWithActions(0);
        toolbar.setContentInsetsAbsolute(0, 0);
        toolbar.setPadding(0, 0, 0, 0);

getCustomView().getParent() 是关键所在。

0

在你的代码中加入这两行

Toolbar toolbar=(Toolbar)viewActionBar.getParent();
toolbar.setContentInsetsAbsolute(0,0);

0
对于仍然遇到此问题的任何人,除了将插图设置为0之外,还应将工具栏的填充设置为0。
supportActionBar?.customView?.apply {
            (parent as Toolbar?)?.setContentInsetsAbsolute(0,0)
            (parent as Toolbar?)?.setContentInsetsRelative(0,0)
            (parent as Toolbar?)?.setPadding(0)
        }

0
今天我也遇到了这个问题,后来发现我的项目中有一个res/values-v21/styles.xml文件,这是由Android Studio自动生成的,这就是问题所在。
为什么呢?
因为我的res/values-v21/styles.xml文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="BaseAppTheme" parent="android:Theme.Material.Light">
    </style>
</resources>

我的res/values/styles.xml文件包含了以下内容:

<style name="BaseAppTheme" parent="android:Theme.Holo.Light">
    <!-- Customize your theme here. -->
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:soundEffectsEnabled">false</item>
</style>

当我在Lollipop上运行我的应用程序时,使用了res/values-v21/styles.xml,这导致了OP遇到的确切问题。 所以我想到了一个简单的解决方法,就是删除它:
    <style name="BaseAppTheme" parent="android:Theme.Material.Light">
    </style>

res/values-v21/styles.xml


0

言归正传:

 ActionBar actionBar = getSupportActionBar();
                actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
                actionBar.setCustomView(R.layout.actionbar_layout);
                Toolbar toolbar = (Toolbar) actionBar.getCustomView().getParent();
                    toolbar.setContentInsetsAbsolute(0, 0);
                    toolbar.setPadding(0, 0, 0, 0);

确保导入正确的工具栏 - android.support.v7.widget.Toolbar;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接