Android: jak uzyskać bieżące przesunięcie X RecyclerView?
Używam Scrollview
do nieskończonej "karuzeli wybierającej czas" i okazało się, że nie jest to najlepsze podejście (ostatnie pytanie )
Teraz znalazłem widok Recyclera ale nie jestem w stanie uzyskać bieżącego przesunięcia przewijania w kierunku X widoku recyclerView? (Załóżmy, że każdy element ma szerokość 100px, a drugi element jest widoczny tylko do 50%, więc przesunięcie przewijania wynosi 150px)
- Wszystkie elementy mają tę samą szerokość, ale jest jakaś przerwa przed pierwszą, po ostatniej pozycji
-
recyclerView.getScrollX()
zwraca0
(dokumenty mówią: początkowa wartość przewijania) -
LayoutManager
mAfindFirstVisibleItemPosition
, ale nie mogę obliczyć przesunięcia X z tym
UPDATE
Właśnie znalazłem sposób na śledzenie pozycji X, aktualizując wartość za pomocą wywołania zwrotnego onScrolled
, ale wolałbym uzyskać rzeczywistą wartość zamiast śledzić ją cały czas!
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);
}
});
6 answers
RecyclerView ma już metodę, aby uzyskać poziome i pionowe przesunięcie przewijania
mRecyclerView.computeHorizontalScrollOffset()
mRecyclerView.computeVerticalScrollOffset()
Będzie to działać dla Recyclerviewów zawierających komórki o tej samej wysokości (dla pionowego przesunięcia przewijania) i tej samej szerokości (dla poziomego przesunięcia przewijania)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-07 08:11:11
Rozwiązanie 1: setOnScrollListener
Zapisz swoją pozycję X jako zmienną klasy i aktualizuj każdą zmianę w onScrollListener
. Upewnij się, że nie zresetujesz 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);
}
});
Rozwiązanie 2: Oblicz aktualną pozycję.
W moim przypadku, mam poziomą listę, która jest wypełniona wartościami czasu(0:00, 0:30, 1:00, 1:30 ... 23:00, 23:30). Obliczam czas z pozycji czasu, która znajduje się na środku ekranu (punkt obliczeniowy). Dlatego ja potrzebujesz dokładnej pozycji X-scrolla mojego RecycleView
- każdy element czasu ma tę samą szerokość 60dp (fyi: 60dp = 30min, 2DP = 1min)
-
Pierwszy element (element nagłówka) ma dodatkowe wypełnienie, aby ustawić 0min na środku
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); } });
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-26 08:28:15
Podziękowania dla @ umar-qureshi za właściwą przewagę! Wygląda na to, że można określić procent przewijania za pomocą Offset
, Extent
, i Range
takie, że
percentage = 100 * offset / (range - extent)
Na przykład (do umieszczenia w 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 + "%");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-08 02:21:57
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();
}
}
Niż gdzie trzeba uzyskać offset:
recyclerView.getHorizontalOffset()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-20 22:48:27
Jeśli chcesz znać bieżącą stronę i jej przesunięcie w stosunku do szerokości RecyclerView, możesz spróbować czegoś takiego:
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);
}
}
});
Jeśli currentPage
ma indeks 0, to leftIndicator
(strzałka) będzie przezroczysta, podobnie będzie i rightIndicator
jeśli jest tylko jeden page
(w przykładzie adapter zawsze ma co najmniej jeden element do pokazania, więc nie ma sprawdzania pustej wartości).
W ten sposób będziesz w zasadzie miał prawie taką samą funkcjonalność, jak gdybyś używał callback pageScrolled
od ViewPager.OnPageChangeListener
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-17 00:46:57
Poprzez nadpisanie RecyclerView onScrolled(int dx,int dy)
, można uzyskać przesunięcie przewijania. ale gdy dodasz lub usuniesz element, wartość może być nieprawidłowa.
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;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-30 06:42:41