最近看到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; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
我正在为一个项目使用RichTextFX,并想在RichTextFX中的代码区背景中添加一个画布。我已经这样做了,但是我还没有找到一种方法让它在代码区本身滚动。 有没有一种方法可以通过编程获得代码区的滚动位置,这样我就可以做到这一点?
本文向大家介绍jQuery实现滚动条滚动到子元素位置(方便定位),包括了jQuery实现滚动条滚动到子元素位置(方便定位)的使用技巧和注意事项,需要的朋友参考一下 话不多说,请看代码: jQuery: 以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持呐喊教程!
我有一个页面的正文在滚动。也就是说,body上的滚动事件侦听器起作用。但是,window和document上的滚动侦听器不会激发。 问题是,即使body是滚动的,$(“body”).scrolltop()始终返回0。我循环遍历了body的所有子级,没有一个scrollTop()大于0。有些孩子有溢出:隐藏,但应该不会影响滚动顶部,我猜。 我删除了高度:100%根据这个问题,我也经历了这个问题。 我
我用GridLayoutManager实现了一个RecyclerView,它有垂直和水平滚动,我需要将布局滚动到特定的位置,引用了很多代码,但对我来说没有效果。 Java类代码: XML: 只有在添加了垂直和水平滚动的嵌套滚动视图后,滚动才能在两个方向上顺利工作。现在我需要滚动到特定的位置。 谢谢您
我有一个从Firebase数据库检索数据的简单片段。我使用firebase recycler视图显示检索数据。在滚动或屏幕旋转后,我无法强制回收器视图(或线性布局管理器)恢复滚动位置。 我在这里找到了一些答案,但它们不起作用。 我的代码是: 公共类NewsListFragment扩展了ParentNewsFragment{ } 最后的showToast方法显示了位置的真实数量,但recyclerv
如何使用纯javascript或angularjs使用水平/溢出-x设置div滚动的x位置?重要提示:我不是在寻找jquery解决方案——使用angularjs,jquery不会立即工作。 $anchorScroll()在angularjs中滚动到垂直位置,但不滚动到水平位置afaik。$window.scroll或window.scrollTo(x, y)不滚动溢出x div。如果这里有人确信我
本文向大家介绍JavaScript控制网页平滑滚动到指定元素位置的方法,包括了JavaScript控制网页平滑滚动到指定元素位置的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JavaScript控制网页平滑滚动到指定元素位置的方法。分享给大家供大家参考。具体如下: 使用方法: 页面将会平滑的滚动到元素elementID所在的位置 希望本文所述对大家的javascript程序设计有所
本文向大家介绍js实现滚动条滚动到某个位置便自动定位某个tr,包括了js实现滚动条滚动到某个位置便自动定位某个tr的使用技巧和注意事项,需要的朋友参考一下 要实现带滚动条的table,定位到某个tr,其实是很简单的,只有几行js代码就可以完成,具体内容如下 js代码 html 效果图: 虽说是几行代码,但要彻底弄懂。要熟悉animate的使用,scrollTop,.offsetTop的意思方可得心