RecyclerView滚动视图显示延迟及CoordinatorLayout文本滚动显隐问题
针对你的两个Android UI问题的解决方案
我来帮你搞定这两个常见的Android开发问题,都是实际项目里容易碰到的,下面分情况给你说清楚解决方案:
问题1:RecyclerView滚动时视图显示延迟、卡顿
滚动延迟卡顿大多是因为布局或数据绑定的开销太大,或者内存占用过高导致的,你可以从这几个方向优化:
- 优化Item布局结构:别用多层嵌套的LinearLayout,换成ConstraintLayout能大幅减少布局的测量和绘制时间。另外如果Item的高度是固定的,直接给
android:layout_height设固定值,避免RecyclerView每次滚动都重新计算布局大小。 - 规范ViewHolder的使用:在
onBindViewHolder里只做数据绑定,别在这里搞图片加载、复杂计算这种耗时操作。一定要用setTag复用视图,别每次都调用findViewById,那玩意儿特别费性能。 - 图片加载要讲究:如果Item里有图片,必须用Glide或者Picasso这类图片加载库,它们会自动帮你压缩图片、做内存和磁盘缓存,避免加载大图把内存撑爆导致卡顿。同时给图片设置占位图,防止滚动时图片突然加载让布局跳来跳去。
- 减少过度绘制:去开发者选项里开“显示过度绘制区域”,如果Item有大面积的红色区域,说明过度绘制严重,赶紧把多余的父布局背景去掉,或者优化视图层级。
- 调整RecyclerView的参数:如果Item高度固定,一定要加
mProductListView.setHasFixedSize(true),这样RecyclerView就不用每次滚动都重新计算布局了。另外可以用setItemViewCacheSize(10)(数值按需调整)增加视图缓存的数量,减少创建ViewHolder的次数。
问题2:CoordinatorLayout中TextView随滚动显示/隐藏
你已经用了RecyclerView的滚动监听器,不过逻辑可以再完善下,另外还有更优雅的CoordinatorLayout原生方案,两种都给你说:
方案1:完善滚动监听器的逻辑
核心是判断滚动方向,并且用动画实现平滑的显示/隐藏,别直接调用setVisibility,那样太生硬:
// 先定义变量记录上一次的滚动位置,还有触发变化的阈值 private int lastScrollPosition = 0; private static final int SCROLL_THRESHOLD = 20; mProductListView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // dy>0是向上滚,dy<0是向下滚 int currentScrollPos = recyclerView.computeVerticalScrollOffset(); // 滚动超过阈值才触发,避免轻微滚动就来回切换 if (Math.abs(currentScrollPos - lastScrollPosition) > SCROLL_THRESHOLD) { if (currentScrollPos > lastScrollPosition) { // 向上滚动,隐藏TextView hideTextView(); } else { // 向下滚动,显示TextView showTextView(); } lastScrollPosition = currentScrollPos; } } @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); // 这里可以处理滚动停止时的逻辑,比如如果停在顶部就强制显示TextView if (newState == RecyclerView.SCROLL_STATE_IDLE && recyclerView.computeVerticalScrollOffset() == 0) { showTextView(); } } }); // 平滑隐藏的动画方法 private void hideTextView() { if (yourTextView.getVisibility() == View.VISIBLE) { yourTextView.animate() .translationY(-yourTextView.getHeight()) .setDuration(300) .setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) {} @Override public void onAnimationEnd(Animator animator) { yourTextView.setVisibility(View.INVISIBLE); } @Override public void onAnimationCancel(Animator animator) {} @Override public void onAnimationRepeat(Animator animator) {} }); } } // 平滑显示的动画方法 private void showTextView() { if (yourTextView.getVisibility() != View.VISIBLE) { yourTextView.setVisibility(View.VISIBLE); yourTextView.animate() .translationY(0) .setDuration(300) .setListener(null); } }
方案2:用CoordinatorLayout + AppBarLayout原生实现(更推荐)
如果你的TextView是标题类的元素,直接把它放进AppBarLayout,设置滚动标记,系统会自动处理滚动逻辑,不用自己写监听器:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/your_text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="需要显示/隐藏的文本" android:padding="16dp" app:layout_scrollFlags="scroll|enterAlways"/> </com.google.android.material.appbar.AppBarLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/mProductListView" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </androidx.coordinatorlayout.widget.CoordinatorLayout>
这样设置后,RecyclerView向上滚动时,AppBarLayout(包含你的TextView)会自动平滑隐藏;向下滚动时会自动平滑显示,系统已经帮你处理了所有动画和滚动判断,比自己写监听器稳定多了。
内容的提问来源于stack exchange,提问作者Ravi
相关产品推荐
相关产品推荐

