Android: Как получить текущее смещение X для RecyclerView?
Я использую Scrollview
для бесконечной "Карусели таймера" и выяснил, что это не лучший подход (последний вопрос)
Теперь я нашел Recycler View, но Я не могу получить текущее смещение прокрутки в направлении X recyclerView? (Пусть говорят, что каждый элемент имеет ширину 100 пикселей, а второй - только на 50%, поэтому смещение прокрутки составляет 150 пикселей)
- все элементы имеют одинаковую ширину, но therer - некоторый пробел перед первым, после последнего элемента
-
recyclerView.getScrollX()
возвращает 0
(говорят: начальное значение прокрутки)
-
LayoutManager
имеет findFirstVisibleItemPosition
, но я не могу вычислить смещение X с этим
UPDATE
Я просто нашел способ отслеживать 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);
}
});
Ответы
Ответ 1
![enter image description here]()
Решение 1: setOnScrollListener
Сохраните переменную X-Position как переменную класса и обновите каждое изменение в onScrollListener
. Убедитесь, что вы не reset 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). Я вычисляю время с момента времени, которое находится посередине экрана (точка вычисления). Вот почему мне нужна точная позиция X-Scroll моего RecycleView
- Каждый элемент времени имеет ту же ширину 60dp (fyi: 60dp = 30min, 2dp = 1min)
-
Первый элемент (элемент заголовка) имеет дополнительное дополнение, чтобы установить 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 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 why I have to subtract it again)
leftScrollXCalculated = (mHeaderItemWidth - mCellWidth) + firstItemPosition * mCellWidth + firstVisibleItem.getLeft();
}
Log.i("asdf","calculated X to left = " + leftScrollXCalculated);
}
});
}
Ответ 2
RecyclerView уже имеет способ получить горизонтальное и вертикальное смещение прокрутки
mRecyclerView.computeHorizontalScrollOffset()
mRecyclerView.computeVerticalScrollOffset()
Это будет работать для RecyclerViews, содержащих ячейки с одинаковой высотой (для вертикального сдвига прокрутки) и той же ширины (для горизонтального сдвига прокрутки)
Ответ 3
Спасибо @umar-qureshi за правильный лидер! По-видимому, вы можете определить процент прокрутки с помощью Offset
, Extent
и Range
, чтобы
percentage = 100 * offset / (range - extent)
Например (для размещения OnScrollListener
):
int offset = recyclerView.computeVerticalScrollOffset();
int extent = recyclerView.computeVerticalScrollExtent();
int range = recyclerView.computeVerticalScrollRange();
int percentage = (int)(100.0 * offset / (float)(range - extent));
Log.i("RecyclerView, "scroll percentage: "+ percentage + "%");
Ответ 4
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()
Ответ 5
переопределив 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 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;
}
}