targetSdkVersion 30下RecyclerView adjustResize失效,EditText被IME遮挡
这是Android 11(API 30)调整了窗口Insets计算逻辑,和RecyclerView旧版本IME弹出适配逻辑缺陷共同导致的问题:当RecyclerView高度设为wrap_content且内容总高度超过屏幕高度时,adjustResize触发窗口高度变化后,RecyclerView不会主动调整滚动位置让获得焦点的EditText展示在IME上方,只有当内容完全可见时才会正常适配。
方案1:修改RecyclerView布局参数(最简单,优先使用)
把activity_main.xml中RecyclerView的layout_height属性从wrap_content改为match_parent即可解决绝大多数场景的问题,修改后的布局代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
原理:match_parent属性让RecyclerView的高度跟随父布局(也就是窗口可用高度)变化,adjustResize触发窗口高度缩减时,RecyclerView会同步重新测量自身高度,并且自动滚动到当前获得焦点的子控件位置。
方案2:升级RecyclerView依赖版本
如果方案1不符合业务需求(必须保留wrap_content属性),可以先尝试升级RecyclerView依赖到1.2.1及以上版本,该版本官方修复了多个API 30下的IME适配问题:
dependencies { implementation "androidx.recyclerview:recyclerview:1.3.2" // 替换为最新稳定版即可 }
方案3:手动监听IME变化滚动到目标位置
如果前两个方案都不适用,可以在Activity中手动监听窗口Insets变化,主动滚动RecyclerView到焦点EditText的位置,代码示例如下:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val myAdapter = MyAdapter() val recyclerView = findViewById<RecyclerView>(R.id.recycler_view) recyclerView.apply { adapter = myAdapter layoutManager = LinearLayoutManager(context) } // 监听窗口Insets变化处理IME弹出 ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { _, insets -> val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom if (imeHeight > 0) { // IME弹出 currentFocus?.let { focusView -> if (focusView is AppCompatEditText) { // 获取EditText对应的item位置 val itemPosition = recyclerView.getChildAdapterPosition(focusView.parent as View) // 滚动到对应位置,可根据需求调整偏移量让EditText完全展示 (recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(itemPosition, 0) } } } insets } myAdapter.items.addAll(listOf(true, true, true)) myAdapter.notifyDataSetChanged() } }
使用该方案需要确保项目引入了core的兼容依赖,支持WindowInsetsCompat相关API。
内容的提问来源于stack exchange,提问作者sehee lee
相关产品推荐
相关产品推荐

