热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

AndroidRecyclerView滚动到中间位置的方法示例

这篇文章主要介绍了AndroidRecyclerView滚动到中间位置的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

最近看到QQ音乐的歌词每次滑动后都可以滚回到中间位置。觉得甚是神奇,打开开发者模式显示布局,发现歌词部分不是采用 android 控件的写的,应该是前端写的。于是,我想,能不能用 recyclerView 实现这个自动回滚到中间位置呢。

功夫不负有心人,查找了一些资料之后,终于搞定了。

下面由我细细讲来。

目标

点击某个条目,在经过4s无任何操作之后,该条目滚动到中间位置显示。点击后,用户在滑动,等用户不操作后再开始延时。用户多次点击,记最后一次点击位置。

分析

首先先考虑,滚动到指定位置是如何操作的?

// 滚动到指定位置
recyclerView.scrollToPosition(position);
// 平滑滚动到指定位置
recyclerView.smoothScrollToPosition(position);

有没有滚动到制定像素位置呢?

// scrollBy(x, y)这个方法是自己去控制移动的距离,单位是像素,所以在使用scrollBy(x, y)需要自己去计算移动的高度或宽度。
recyclerView.scrollBy(x, y)

可是,问题是滚动到中间位置啊?这个怎么办呢?这样子行不行呢?

mRecyclerView.scrollToPosition(0);
mRecyclerView.scrollBy(0,400);

先滚动到制定位置,在滚动一段距离不就好了?运行发现,这两行代码只执行第一行,第二行无效。

debug 调试看了下,还是没有弄懂,实现太复杂。

那就是说这样是不行的,那有没有其他办法呢?

RecyclerView 有一个滚动监听方法:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
      @Override
      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
      }

      @Override
      public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
      }
    });

onScrollStateChanged 方法对应三种状态:静止(SCROLL_STATE_IDLE),拖动滚动(SCROLL_STATE_DRAGGING),滑动(SCROLL_STATE_SETTLING)。

当手动缓慢滑动的时候,会触发: onScrollStateChanged (拖动滚动) --> (n个)onScrolled -->onScrollStateChanged(静止);

当手快速滑动的时候,会触发: onScrollStateChanged (拖动滚动) --> (n个)onScrolled --> onScrollStateChanged (滑动) -->

(n个)onScrolled --> onScrollStateChanged (静止);

有想法了,点击的时候,先运行 scrollToPosition,在 onScrolled 方法里面 运行 scrollBy 方法。写代码,运行,通过。

下面就是中间位置的计算了。

首先计算出 recylerview 的展现高度。

 Rect rect = new Rect();
 mRecyclerView.getGlobalVisibleRect(rect);
 reHeight = rect.bottom - rect.top - vHeight;
当运行 scrollToPosition 后,点击条目就会出现在视野当中,这时候,计算出相应的位移即可。需要注意一点的是,当点击条目在视野内的时候,是不会运行 scrollToPosition 方法的。

    int top = mRecyclerView.getChildAt(position - firstPosition).getTop();
int half = reHeight / 2;
    mRecyclerView.scrollBy(0, top - half);

最后就是延时的设定,采用Handler 进行延时。

代码

核心代码如下:

public class MainActivity extends AppCompatActivity {
  private static final String TAG = "MainActivity";
  private RecyclerView mRecyclerView;
  private LinearLayoutManager mLayoutManager;
  private RecyclerView.Adapter mAdapter;
  private String[] data;
  private Handler handler;
  private boolean isClick = false;
  private static int vHeight = -1;
  private static int reHeight = -1;
  private static int position = 0;
  private static final int target = 10;
  private static boolean isMove = false;
  private Runnable runnable;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    handler = new Handler();

    mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
    //创建默认的线性LayoutManager
    mLayoutManager = new LinearLayoutManager(this);
    mLayoutManager.setAutoMeasureEnabled(true);
    mRecyclerView.setLayoutManager(mLayoutManager);
    //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
    mRecyclerView.setHasFixedSize(true);
    mRecyclerView.setNestedScrollingEnabled(false);
    data = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21"};


    runnable = new Runnable() {
      @Override
      public void run() {
        if (isVisible()) {
          scrollToMiddle();
        } else {
          mRecyclerView.scrollToPosition(position);
          isMove = true;
          isClick = false;
        }
      }
    };

    mAdapter = new MyAdapter(data, new MyAdapter.onRecyclerViewItemClick() {
      @Override
      public void onItemClick(View v, int pos) {
        Toast.makeText(MainActivity.this, "第" + pos + "行", Toast.LENGTH_SHORT).show();
        position = pos;
        vHeight = v.getHeight();

        Rect rect = new Rect();
        mRecyclerView.getGlobalVisibleRect(rect);
        reHeight = rect.bottom - rect.top - vHeight;

        // handler.removeCallbacksAndMessages(null);
        handler.removeCallbacks(runnable);
        handler.postDelayed(runnable, 4000);
        isClick = true;

      }
    });
    mRecyclerView.setAdapter(mAdapter);
    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
      @Override
      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        Log.d(TAG, "" + newState);
        if (newState == RecyclerView.SCROLL_STATE_DRAGGING && !isMove) {
          handler.removeCallbacks(runnable);
        }
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
          if (isClick) {
            handler.postDelayed(runnable, 4000);
          }
        }
      }

      @Override
      public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        if (isMove) {
          if (vHeight <0) {
            isMove = false;
            return;
          }
          scrollToMiddle();
        }
      }
    });
public void scrollToMiddle() {
    final int firstPosition = mLayoutManager.findFirstVisibleItemPosition();
    int top = mRecyclerView.getChildAt(position - firstPosition).getTop();
    Log.d(TAG, " position" + position + " " + top);
    int half = reHeight / 2;
    mRecyclerView.scrollBy(0, top - half);
    isMove = false;

  }

  public boolean isVisible() {
    final int firstPosition = mLayoutManager.findFirstVisibleItemPosition();
    final int lastPosition = mLayoutManager.findLastVisibleItemPosition();
    return position <= lastPosition && position >= firstPosition;
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
    handler = null;
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 探讨 HDU 1536 题目,即 S-Nim 游戏的博弈策略。通过 SG 函数分析游戏胜负的关键,并介绍如何编程实现解决方案。 ... [详细]
  • 本文回顾了2017年的转型和2018年的收获,分享了几家知名互联网公司提供的工作机会及面试体验。 ... [详细]
  • Android Studio 中查看应用程序崩溃日志的方法
    本文介绍如何在 Android Studio 中配置环境变量并使用 ADB 工具查看应用程序的崩溃日志,帮助开发者快速定位和解决问题。 ... [详细]
  • Python自动化测试入门:Selenium环境搭建
    本文详细介绍如何在Python环境中安装和配置Selenium,包括开发工具PyCharm的安装、Python环境的设置以及Selenium包的安装方法。此外,还提供了编写和运行第一个自动化测试脚本的步骤。 ... [详细]
  • 了解责任的苦与乐,是人生的重要课题。本文精选了一系列关于责任的经典语录,帮助读者更深入地理解责任感的重要性,并从中汲取力量。更多相关内容,请继续阅读。 ... [详细]
  • 本文详细介绍如何在 iOS 7 环境下申请苹果开发者账号,涵盖从访问开发者网站到最终激活账号的完整流程。包括选择个人或企业账号类型、付款方式及注意事项等。 ... [详细]
  • 本文详细介绍了如何在Android 4.4及以上版本中配置WebView以实现内容的自动高度调整和屏幕适配,确保中文显示正常,并提供代码示例。 ... [详细]
  • 解决MacOS上Android Studio Gradle版本不匹配问题
    在MacOS系统中,升级Android Studio后可能会遇到Gradle版本不兼容的问题。当网络下载更新受阻时,可以使用本地已安装的Gradle版本来解决问题。本文将详细介绍如何配置本地Gradle环境以确保开发工作的顺利进行。 ... [详细]
  • 本文介绍了如何通过Java代码计算一个整数的位数,并展示了多个基础编程示例,包括求和、平均分计算、条件判断等。 ... [详细]
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • 本篇文章介绍如何将两个分别表示整数的链表进行相加,并生成一个新的链表。每个链表节点包含0到9的数值,如9-3-7和6-3相加得到1-0-0-0。通过反向处理链表、逐位相加并处理进位,最终再将结果链表反向,即可完成计算。 ... [详细]
  • CentOS 系统管理基础
    本文介绍了如何在 CentOS 中查询系统版本、内核版本、位数以及磁盘分区的相关知识。通过这些命令,用户可以快速了解系统的配置和磁盘结构。 ... [详细]
  • 本文详细探讨了 PHP 中 method_exists() 和 is_callable() 函数的区别,帮助开发者更好地理解和使用这两个函数。文章不仅解释了它们的功能差异,还提供了代码示例和应用场景的分析。 ... [详细]
  • 本文探讨了C++编程中理解代码执行期间复杂度的挑战,特别是编译器在程序运行时生成额外指令以确保对象构造、内存管理、类型转换及临时对象创建的安全性。 ... [详细]
author-avatar
ythg
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有