Android AppCompat工具栏在SearchView获得焦点时会拉伸

22

我正在更新一个应用程序,使用新的Toolbar而不是常规的ActionBar。 在我的应用程序中,用户必须能够从他们的联系人列表中选择联系人。为此,我已将SearchView添加到菜单中。 联系人已经在列表中; SearchView用于使用ArrayAdapter.getFilter()方法过滤列表。

当使用ActionBar时,一切都很好,但Toolbar的高度会被拉伸到键盘的后面。使用来自Android Device Monitor的XML检查工具,我可以看到ListView存在于我的键盘后面。

它几乎看起来像SearchView想要显示建议,但我没有配置这样的东西。有什么想法出了问题吗?

图片说明了问题。它们显示了SearchView的正常,展开和聚焦状态。

这是我的XML菜单:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/action_forwarding_contact_search"
        app:showAsAction="always"
        android:title="@string/forwarding_contact_search"
        app:actionViewClass="android.support.v7.widget.SearchView"
        android:icon="@drawable/abc_ic_search_api_mtrl_alpha"/>
</menu>

编辑 固定工具栏的高度并不能解决问题,因为当搜索框 SearchView 获得焦点时,它会消失。更改任一项的重力似乎对 SearchView 没有影响。

正常状态 展开状态 聚焦状态


1
这真的很奇怪和烦人。即使我使用SearchView启动ActionMode,问题仍然会出现在工具栏中。ActionMode栏保持不变,但屏幕的其余部分被填充了ToolBar的颜色。 - ar34z
我只是从主题中删除了 fitsSystemWindows=true 并在 XML 中将其设置为根视图。这很有帮助。 - Deni Erdyneev
10个回答

26

我和原帖作者有同样的问题,我尝试过android:fitsSystemWindows="true"的解决方案,但只解决了一半:搜索框不再扩展,但通知栏(屏幕顶部)变成了完全白色(像布局背景),而不是红色(我的应用主题)。

我找到了一种替代方法,并且它像魅力一样正常工作,所以对于那些遇到困境的人,请尝试以下方法:

在你的清单文件中,在你的Activity部分加入这行代码:

android:windowSoftInputMode="adjustPan"

例如:

<activity
    android:name=".MainActivity"
    android:windowSoftInputMode="adjustPan"
    android:label="My main activity" >
</activity>

19

好的,我搞清楚了。在布局XML中正常放置的普通EditText也会出现相同的问题,因此SearchView没有问题。而Toolbar也不是问题所在。

我创建了一个空活动并尝试更改我的应用程序中的任何内容,最终发现了问题所在:主题设置。在KitKat及以后的版本中,我的主题上有<item name="android:windowTranslucentStatus">true</item>,这样导航抽屉就会出现在状态栏后面。

禁用/删除它可以解决这个问题。这让我想起了android:fitsSystemWindows="true"属性。它被设置在Toolbar上,但没有在包含DrawerLayout的主活动的布局XML中设置。

我猜测DrawerLayout会自动适应系统窗口。例如,在此处没有fitSystemWindows属性:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DashboardActivity">
问题发生的活动中没有导航抽屉,它是一个新活动。在活动布局的根节点上设置 android:fitsSystemWindows="true" 使事情正常工作。
因此,对于任何人阅读此内容:如果您的主题中有 <item name="android:windowTranslucentStatus">true</item> ,请确保包含工具栏的任何根节点都包含 android:fitsSystemWindows="true"
有效示例:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <include layout="@layout/toolbar" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <EditText
                android:id="@+id/editText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true" />

            <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="New Button" />
        </LinearLayout>
</LinearLayout>

我也遇到了这个问题 - 但是我不得不问,如果使用工具栏时我们不能在半透明状态栏后面放置任何东西,那么拥有半透明状态栏的目的是什么? - Tom
1
我成功解决了问题,并通过将工具栏容器包装在另一个不适合SystemWindows的布局中来显示状态栏后面的内容。 - Tom
我本来想说这是不可能的,但你做到了真棒。Play Store应用程序也不会在状态栏后面显示任何内容。我认为“半透明”状态栏的目的是当全屏时可以在其后绘制布局,而无需操作栏/工具栏。 - ar34z
1
很棒的分析。但是另一个问题出现了。当我在根节点上添加android:fitsSystemWindows="true"时,状态栏的沉浸效果消失了。你怎么解决这个问题? - Victor Choy
@VictorChoy 我的情况也是一样的;我发现在清单文件中添加android:windowSoftInputMode="adjustPan",基于Rob的答案,是更可取的解决方案。 - javaxian

17

我也遇到了这样的问题,但上面的回答并没有帮助我,经过大量搜索后,我找到了一些可能会对你有所帮助的东西。

也许这对你有所帮助!

toolbar 中添加以下属性:

android:layout_height="?attr/actionBarSize"

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/ToolBarStyle"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/myPrimaryColor"
android:minHeight="@dimen/abc_action_bar_default_height_material" >

<TextView
    android:id="@+id/toolbar_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:textColor="@color/myTextPrimaryColor"
    android:layout_gravity="center" />

</android.support.v7.widget.Toolbar>

这确实可以防止工具栏扩展,但工具栏标题消失了,而且工具栏的大小太小了 - 即它截断了文本。 - marius bardan
它是在所有设备上发生还是某些特定设备上发生的。如果您使用appcompat,您还可以使用Material Design android:minHeight="@dimen/abc_action_bar_default_height_material" - Kishore Jethava
我曾经见过的最好的解决方案...+1 为我投票感谢。 - Sagar Aghara

3

被接受的答案可以正常工作,但我需要一种替代方案,可以在半透明状态栏下查看工具栏。

问题在于工具栏使用填充来覆盖系统组件。因此,每当键盘出现时,工具栏的paddingBottom被设置为软键盘的高度。解决方案是在调用自定义工具栏类中的super.onMeasure之前重置填充:

public class MyToolbar extends Toolbar {

   (...)

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), 0);
       super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

2

这似乎是一个老问题,但我想解决这个问题的真正原因。

实际上,fitsSystemWindows 不仅将 statusBar 插图添加到您的视图填充中,还包括键盘的高度。因此,当键盘显示时,您的工具栏(它是消耗窗口插图的视图)将获得底部填充,等于您的键盘高度。

将 fitSystemWindows 移动到根节点可以解决此问题,但有时我们无法这样做,例如我们需要工具栏的背景来填充状态栏。

因此,我认为这个问题的真正解决方法是告诉视图只消耗顶部插图。幸运的是,Android 为我们提供了一种方法来实现这一点。

private static final View.OnApplyWindowInsetsListener CONSUME_TOP_INSET_LISTENER = new View.OnApplyWindowInsetsListener() {
    @RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH)
    @Override
    public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
        int b = v.getPaddingBottom();
        int l = v.getPaddingLeft();
        int r = v.getPaddingRight();

        v.setPadding(l, insets.getSystemWindowInsetTop(), r, b);
        int il = insets.getSystemWindowInsetLeft();
        int ir = insets.getSystemWindowInsetRight();
        int ib = insets.getSystemWindowInsetBottom();
        return insets.replaceSystemWindowInsets(il, 0, ir, ib);
    }
};
public static void makeViewConsumeTopWindowInsetsOnly(@NonNull View view) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
        view.setOnApplyWindowInsetsListener(CONSUME_TOP_INSET_LISTENER);
    }
}

将上述代码添加到某个位置,并使用您想要消耗顶部插图的视图调用此方法。

1

我在使用带有TextView和Spinner的Toolbar中的SearchView时遇到了相同的问题。关闭SearchView(通过按下Toolbar返回按钮或切换到ViewPager中的不同选项卡)会导致Toolbar延伸到键盘顶部以下。

我通过在我的Toolbar中的视图周围放置额外的布局来解决了这个问题。

之前:

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

        <TextView             
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <Spinner
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

</android.support.v7.widget.Toolbar>

之后

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <TextView 
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

        <Spinner             
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </LinearLayout>

</android.support.v7.widget.Toolbar>

1
我遇到了类似的问题,将 showAsAction="always|collapseActionView" 设置在搜索菜单项(menu.xml)内解决了工具栏拉伸的问题。

1

最简单的解决方案是不更改 XML 并保持半透明的系统栏,方法是添加:

kotlin:
toolbar.setOnApplyWindowInsetsListener { toolbar, windowInsets ->
    toolbar.updatePadding(
        windowInsets.systemWindowInsetLeft, 
        windowInsets.systemWindowInsetTop,
        windowInsets.systemWindowInsetRight,
        0
    )
    windowInsets.consumeSystemWindowInsets()
}

请检查您的fitsSystemWindows=true是否正确放置。

现在由于支持显示切口,这是正确的解决方案。当键盘打开时,systemWindowInsetBottom大于0,导致OP提到的行为。使用此解决方案,您可以将底部填充修复为0(不再附加到systemWindowInsetBottom)。 - guipivoto

0

如果你在工具栏中使用EditText,将"flagNoExtractUi"添加到imeOptions中,可以解决拉伸编辑区域的问题。

用于搜索操作的EditText而不会拉伸:

android:id="@+id/toolbar_editText"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:inputType="text"
android:imeOptions="actionSearch|flagNoExtractUi"
android:singleLine="true" />


0

我想分享我的经验,但在此之前,我想先发表一下评论。到目前为止,我真的发现这个CoordinatorLayout有点问题,不值得被放入SDK中。它只是有点问题。当它表现得如此不稳定时,xml布局上的架构并没有太大帮助来弄清楚发生了什么。我虔诚地遵循了示例,但它们都没有起作用。

话虽如此,我正在使用版本为v24.0.2(本文撰写时最新版本)的构建工具,我的情况可能与其他人不同。因此,我将此答案与其他答案一起发布。

在我的情况下,我正在使用这个来进行导航抽屉。

正如一些答案所指出的那样,这是导航抽屉。我尝试不使用该库仍然存在问题。我将CoordinatorLayout作为我的两个活动的父布局,并按照库作者的指示以编程方式插入NavigationDrawer。当聚焦于EditText时,扩展的Toolbar大小仍然与屏幕大小相同。因此,在我的情况下,问题并非来自那里。

以下是我在这种情况下所做的:

我从活动的CoordinatorLayout布局中删除了fitsSystemWindows。与其他人在这里建议的相反。

我在此处粘贴了整个活动布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coordinatorlayout_homescreen"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.HomeScreenActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsingtoolbarlayout_homescreen"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="64dp"
            app:expandedTitleMarginEnd="48dp"
            app:layout_scrollFlags="scroll|enterAlwaysCollapsed">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar_homescreen"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="pin"/>

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <FrameLayout
            android:id="@+id/framelayout_homescreen"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.NestedScrollView>

    <!--
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab_homescreen"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />
    -->

</android.support.design.widget.CoordinatorLayout>

我在另一个活动中做了这个,它按预期工作。我不再有可扩展的工具栏了。但是出现了问题。我快要抓狂了。状态栏变成了白色。Phoenix Wang在那篇帖子中的解决方案为我解决了问题,我引用他的答案:

I found the answer in this link:Status Bar Color not changing with Relative Layout as root element

So it turns out we need remove the

  <item name="android:statusBarColor">@android:color/transparent</item> in

styles.xml(v21). And it works just fine for me.

我的唯一担忧是这个解决方案在未来的更新中会如何保持稳定。 CoordinatorLayout 不应该表现出这样的行为。


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