Android 当 searchview 获得焦点时,appcompat 工具栏会伸展

Android appcompat toolbar stretches when searchview gets focus

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

使用 ActionBar 一切正常,但 Toolbar 的高度被拉伸到键盘后面。使用 Android 设备监视器的 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>

编辑 给 Toolbar 一个固定的高度并不能解决问题,因为它会使 SearchView 在获得焦点时消失。更改任一项目的重力似乎对 SearchView.

没有影响

好的,我明白了。 SearchView 没有问题,因为普通的 EditText 也会发生同样的问题,它们通常被放置在布局 xml 中。 Toolbar 也不是问题。

我创建了一个空的 activity 并尝试了我在我的应用程序中更改的所有内容,最终找到了我的主题。在 KitKat 和后来的主题上我设置了 <item name="android:windowTranslucentStatus">true</item>,所以导航抽屉会出现在状态栏后面。

Disabling/removing 这将解决问题。这让我想起了android:fitsSystemWindows="true"属性。它设置在 Toolbar 上,但不在包含 DrawerLayout 的主要 activity 的布局 xml 中。 我想 DrawerLayout 将自己设置为适合系统 windows。 例如。这里没有 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">

出现问题的activity没有NavigationDrawer,是新的activity。在 activity 布局的根节点上设置 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>

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

问题是工具栏使用填充来覆盖系统组件。因此,只要出现键盘,工具栏的 paddingBottom 就会被设置为软键盘的高度。解决方案是在我的自定义工具栏 class:

中调用 super.onMeasure 之前重置填充
public class MyToolbar extends Toolbar {

   (...)

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

我遇到了与 OP 相同的问题,我尝试了 android:fitsSystemWindows="true" 解决方案,但只解决了一半:搜索视图不再展开,但通知栏(屏幕顶部)变成全白(如布局背景)而不是红色(我的应用程序主题)。

我找到了另一种方法,它非常有效,所以对于那些被卡住的人,试试这个:

在您的清单中,只需将此行添加到您的 activity 部分:

android:windowSoftInputMode="adjustPan"

示例:

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

我在工具栏上的 SearchView 中遇到了同样的问题,其中包含 TextView 和 Spinner。关闭 SearchView(通过按工具栏后退按钮或切换到 ViewPager 中的不同选项卡)会导致工具栏延伸到键盘顶部的正下方。

我通过在我的工具栏中的视图周围放置一个额外的布局来解决它。

之前:

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

我遇到了类似的问题,但对以上答案没有帮助,但经过大量搜索后找到了一些东西。

也能帮到你!!

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>

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

我想分享我的经验,但在此之前我想放弃此评论。到目前为止,我真的发现这个 CoordinatorLayout 恶作剧有问题,不值得在 SDK 中删除。它只是越野车。当它表现得像这样不稳定时,xml 布局上的架构对弄清楚发生了什么没有多大帮助。我虔诚地追随 examples,他们中的 none 工作了。

话虽如此,我使用的是构建工具版本 v24.0.2(撰写本文时的最新版本),我的情况可能与其他人不同。所以我把这个答案和其他答案一起放在这里。

就我而言,我将此 library 用于 NavigationDrawer

正如这里的一些答案所指出的,它是导航抽屉。我试着不使用那个库,但仍然有问题。我将 CoordinatorLayout 作为我的两个活动的父布局,并按照库作者的指示以编程方式插入 NavigationDrawer。专注于 EditText 时屏幕的扩展 Toolbar 大小仍然存在。因此,就我而言,问题不在于此。

这是我在我的案例中所做的:

我从 activity 的 CoordinatorLayout 布局中删除了 fitsSystemWindows。与此处其他人的建议相反。

我在此处粘贴我的整个 activity 布局:

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

我在另一个 activity 上做了这个,它按预期工作。我没有扩展 Toolbar 了。但是这个 发生了。我正要拔头发。状态栏变成了白色。 Phoenix Wang 的解决方案 post 帮我解决了,我引用他的回答:

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 不应该那样做。

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

没有拉伸的搜索操作的编辑文本:

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

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

事实上,fitsSystemWindows 不仅将 statusBar insets 添加到您的视图填充中,而且还添加了键盘的高度。因此,当键盘显示时,您的工具栏(即使用 window 插图的视图)将获得等于键盘高度的底部填充。

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

将上面的代码添加到某个地方,并用你想要消耗顶部插图的视图调用这个方法。

无需更改 xml 并保持半透明系统栏的最简单解决方案是添加: 科特林:

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

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