我使用Scrollview
进行无限时间选择器轮播"并发现,这不是最好的方法(last question)
现在,我找到了Recycler View,但我无法在recyclerView的X方向上获得当前的滚动偏移? (假设每个项目的宽度为100px,第二个项目只有50%可见,因此滚动偏移量为150px)
recyclerView.getScrollX()
返回0
(文档说:初始滚动值)LayoutManager
有findFirstVisibleItemPosition
,但我无法用更新
我刚刚找到了一种跟踪X-Position的方法,同时使用onScrolled
回调更新了值,但我更愿意获取实际值,而不是一直跟踪它!
private int overallXScroll = 0;
//...
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
overallXScroll = overallXScroll + dx;
Log.i("check","overallXScroll->" + overallXScroll);
}
});
答案 0 :(得分:53)
RecyclerView已经有获取水平和垂直滚动偏移的方法
mRecyclerView.computeHorizontalScrollOffset()
mRecyclerView.computeVerticalScrollOffset()
这适用于包含相同高度(垂直滚动偏移)和相同宽度(水平滚动偏移)的单元格的RecyclerViews
答案 1 :(得分:47)
解决方案1: setOnScrollListener
将您的X-Position保存为类变量,并更新onScrollListener
中的每个更改。确保您不重置overallXScroll
(f.e。onScreenRotationChange
)
private int overallXScroll = 0;
//...
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
overallXScroll = overallXScroll + dx;
Log.i("check","overall X = " + overallXScroll);
}
});
解决方案2:计算当前位置。
在我的情况下,我有一个水平列表,其中填充了时间值(0:00,0:30,1:00,1:30 ...... 23:00,23:30)。我正在计算时间项目的时间,该时间项目位于屏幕中间(计算点)。这就是我需要RecycleView
第一项(标题项)有一个额外的填充,将0分钟设置为中心
private int mScreenWidth = 0;
private int mHeaderItemWidth = 0;
private int mCellWidth = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//init recycle views
//...
LinearLayoutManager mLLM = (LinearLayoutManager) getLayoutManager();
DisplayMetrics displaymetrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
this.mScreenWidth = displaymetrics.widthPixels;
//calculate value on current device
mCellWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources()
.getDisplayMetrics());
//get offset of list to the right (gap to the left of the screen from the left side of first item)
final int mOffset = (this.mScreenWidth / 2) - (mCellWidth / 2);
//HeaderItem width (blue rectangle in graphic)
mHeaderItemWidth = mOffset + mCellWidth;
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//get first visible item
View firstVisibleItem = mLLM.findViewByPosition(mLLM.findFirstVisibleItemPosition());
int leftScrollXCalculated = 0;
if (firstItemPosition == 0){
//if first item, get width of headerview (getLeft() < 0, that's why I Use Math.abs())
leftScrollXCalculated = Math.abs(firstVisibleItem.getLeft());
}
else{
//X-Position = Gap to the right + Number of cells * width - cell offset of current first visible item
//(mHeaderItemWidth includes already width of one cell, that's why I have to subtract it again)
leftScrollXCalculated = (mHeaderItemWidth - mCellWidth) + firstItemPosition * mCellWidth + firstVisibleItem.getLeft();
}
Log.i("asdf","calculated X to left = " + leftScrollXCalculated);
}
});
}
答案 2 :(得分:28)
感谢@ umar-qureshi的正确领导!您似乎可以使用array1
,Offset
和Extent
确定滚动百分比,以便
Range
例如(要放入percentage = 100 * offset / (range - extent)
):
OnScrollListener
答案 3 :(得分:8)
public class CustomRecyclerView extends RecyclerView {
public CustomRecyclerView(Context context) {
super(context);
}
public CustomRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public int getHorizontalOffset() {
return super.computeHorizontalScrollOffset();
}
}
比你需要获得偏移的地方:
recyclerView.getHorizontalOffset()
答案 4 :(得分:3)
如果你需要知道当前页面及其偏移量与RecyclerView的宽度相比,你可能想尝试这样的事情:
recyclerView.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);
final int scrollOffset = recyclerView.computeHorizontalScrollOffset();
final int width = recyclerView.getWidth();
final int currentPage = scrollOffset / width;
final float pageOffset = (float) (scrollOffset % width) / width;
// the following lines just the example of how you can use it
if (currentPage == 0) {
leftIndicator.setAlpha(pageOffset);
}
if (adapter.getItemCount() <= 1) {
rightIndicator.setAlpha(pageOffset);
} else if (currentPage == adapter.getItemCount() - 2) {
rightIndicator.setAlpha(1f - pageOffset);
}
}
});
如果currentPage
的索引为0,那么leftIndicator
(箭头)将是透明的,如果只有一个rightIndicator
,那么page
将是透明的(在示例中,适配器始终至少有一个要显示的项目,因此不会检查空值。
通过这种方式,您基本上可以使用与pageScrolled
中使用回调ViewPager.OnPageChangeListener
几乎相同的功能。
答案 5 :(得分:0)
通过覆盖RecyclerView onScrolled(int dx,int dy)
,您可以获得滚动偏移量。但是当您添加或删除该项时,该值可能是错误的。
public class TempRecyclerView extends RecyclerView {
private int offsetX = 0;
private int offsetY = 0;
public TempRecyclerView(Context context) {
super(context);
}
public TempRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public TempRecyclerView(Context context, @Nullable AttributeSet attrs,int defStyle){
super(context, attrs, defStyle);
}
/**
* Called when the scroll position of this RecyclerView changes. Subclasses
should usethis method to respond to scrolling within the adapter's data
set instead of an explicit listener.
* <p>This method will always be invoked before listeners. If a subclass
needs to perform any additional upkeep or bookkeeping after scrolling but
before listeners run, this is a good place to do so.</p>
*/
@Override
public void onScrolled(int dx, int dy) {
// super.onScrolled(dx, dy);
offsetX+=dx;
offsetY+=dy;
}
}