You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android AppBar配合Toolbar实现SearchView动效及适配问题

我目前正在Android平台开发搜索栏功能,实现思路参考了这篇帖子,希望在原有实现基础上扩展更多功能。上述帖子的核心实现逻辑简述如下:SearchView初始位于屏幕中部,当SearchView获取焦点时通过动画移动至屏幕顶部,失去焦点后通过动画回归初始位置。我希望实现的效果为:页面初始加载时即显示返回箭头,效果如图1所示

图1

初始状态效果

当SearchView获取焦点时,界面需要呈现为图2所示效果

图2

聚焦状态效果

我尝试编写了部分代码,但未能实现预期效果,相关代码如下:

相关代码实现

ExploreConsultationsLayoutBinding.xml

<androidx.coordinatorlayout.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:layout_width="match_parent"
  android:layout_height="match_parent"
  android:focusable="true">


  <com.google.android.material.appbar.AppBarLayout
    android:id="@+id/appBar"
    android:layout_width="match_parent"
    android:gravity="bottom"
    android:backgroundTint="@color/red_primary_80"
    android:layout_height="?attr/collapsingToolbarLayoutLargeSize"
    android:fitsSystemWindows="true">

      <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/black">

    <androidx.appcompat.widget.SearchView
        android:id="@+id/searchView"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_marginStart="16dp"
        app:iconifiedByDefault="false"
        android:layout_marginEnd="16dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
     />

     </androidx.appcompat.widget.Toolbar>

   </com.google.android.material.appbar.AppBarLayout>


             <!-- 可滚动内容 -->

</androidx.coordinatorlayout.widget.CoordinatorLayout>

ExploreConsultationsActivity.kt

package com.example.app.consultation

import android.content.Context
import android.graphics.Rect
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.widget.SearchView
import com.example.app.common.BaseActivity
import com.example.app.databinding.ExploreConsultationsLayoutBinding
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf

class ExploreConsultationsActivity : BaseActivity() {

    companion object {
        const val CONSULTATION_LIST_KEY = "consultation_list"
    }

    private val binding by lazy { ExploreConsultationsLayoutBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        setupView()
    }

    fun setupView() {
        hideActionBar()
        setupSearchView()
    }

    fun hideActionBar() {
        supportActionBar?.let { actionBar ->
            actionBar.hide()
        }
    }

    fun setupSearchView() {
        binding.consultationSearchView.apply {
            setOnQueryTextListener(object : SearchView.OnQueryTextListener {
                override fun onQueryTextSubmit(query: String?) = false
                override fun onQueryTextChange(newText: String?): Boolean {
                    if (newText != null) {
                        viewModel.queryText = newText
                    }
                    return true
                }
            })
            setOnQueryTextFocusChangeListener { view, hasFocus ->
                binding.appBar.setExpanded(!hasFocus)
                if (hasFocus) {
                    binding.toolbar.apply {
                        setSupportActionBar(this)
                        supportActionBar?.setDisplayHomeAsUpEnabled(true)
                    }
                } else {
                    supportActionBar?.setDisplayHomeAsUpEnabled(false)
                }
                isSelected = hasFocus
            }
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        if (ev?.action == MotionEvent.ACTION_DOWN) {
            val view: View? = currentFocus
            if (view is SearchView.SearchAutoComplete) {
                val outRect = Rect()
                view.getGlobalVisibleRect(outRect);
                if (!outRect.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
                    view.clearFocus()
                    val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
                }
            }
        }
        return super.dispatchTouchEvent(ev)
    }
}

Mainfest.xml

<activity android:name="ExploreConsultationsActivity"
            android:screenOrientation="portrait"
            android:theme="@style/NoActionBar"/>

Style.xml

<style name="NoActionBar" parent="@style/Theme.MaterialComponents.Light.NoActionBar">
        <item name="colorPrimary">@color/abc</item>
        <item name="colorPrimaryDark">@color/xyz</item>
        <item name="colorAccent">@color/abc</item>
        <item name="android:theme">@style/AppTheme</item>
        <item name="android:colorBackground">@color/white</item>
        <item name="android:windowActionBar">false</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:statusBarColor">@color/status_bar</item>
        <item name="android:windowLightStatusBar" tools:ignore="NewApi">true</item>
</style>
实际运行效果

实际效果1
实际效果2

预期效果

即问题开头展示的图1、图2效果。
参考实现项目:ToolbarApplication

问题更新

边距问题示意图
目前SearchView距离状态栏过近,请问该如何为其设置顶部margin或padding?


内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:45:31