Android在ListView中获取确切的滚动位置

我想获得ListView滚动的确切,像素位置。 不,我不是指第一个可见的位置。

有没有办法做到这一点?

好的,我find了一个解决方法,使用下面的代码:

View c = listview.getChildAt(0); int scrolly = -c.getTop() + listview.getFirstVisiblePosition() * c.getHeight(); 

它的工作方式是将第一个可见列表项目的实际偏移量计算出来,然后计算它离视图顶部的距离,以确定我们“滚动”到视图的多less,所以现在我们知道可以计算其余的则使用常规的getFirstVisiblePosition方法。

Saarraz1的答案只有在列表视图中的所有行高度相同且没有标题(或者与行高度相同)的情况下才有效。

请注意,一旦行的消失在屏幕的顶部,你不能访问他们,因为你将无法跟踪他们的身高。 这就是为什么你需要保存这些高度(或所有的累积高度)。 我的解决scheme需要保持每个索引的高度字典(假设列表显示时,第一次滚动到顶部)。

 private Dictionary<Integer, Integer> listViewItemHeights = new Hashtable<Integer, Integer>(); private int getScroll() { View c = listView.getChildAt(0); //this is the first visible row int scrollY = -c.getTop(); listViewItemHeights.put(listView.getFirstVisiblePosition(), c.getHeight()); for (int i = 0; i < listView.getFirstVisiblePosition(); ++i) { if (listViewItemHeights.get(i) != null) // (this is a sanity check) scrollY += listViewItemHeights.get(i); //add all heights of the views that are gone } return scrollY; } 

我想到的最简单的想法是扩展ListView,并公开受默认保护的“computeVerticalScrollOffset”,然后在你的xml布局中使用“com.your.package.CustomListView”。

 public class CustomListView extends ListView { public CustomListView(Context context) { super(context); } public CustomListView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public int computeVerticalScrollOffset() { return super.computeVerticalScrollOffset(); } } 

如果其他人在Google中find这个方法,同时寻找一种方式来跟踪OnScrollListener中的相对滚动偏移量 – 也就是说,自从上次调用监听器之后Y发生了变化 – 这是一个显示如何计算的Gist 。

首先声明你的intvariables来保存位置。

 int position = 0; 

然后将scrollListener添加到您的ListView,

 listView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { position = firstVisibleItem; } }); 

然后,在获得新的数据或数据的任何更改后,您需要设置列表查看当前位置

 listView.setSelection(position); 

我已经使用安装我的适配器后,对我来说工作正常..

我知道我迟到了,但我觉得分享我的解决scheme来解决这个问题。 我有一个ListView,我试图find多less滚动,以滚动相关的东西,并导致视差效应。 这是我的解决scheme:

 public abstract class OnScrollPositionChangedListener implements AbsListView.OnScrollListener { int pos; int prevIndex; int prevViewPos; int prevViewHeight; @Override public void onScroll(AbsListView v, int i, int vi, int n) { try { View currView = v.getChildAt(0); int currViewPos = Math.round(currView.getTop()); int diffViewPos = prevViewPos - currViewPos; int currViewHeight = currView.getHeight(); pos += diffViewPos; if (i > prevIndex) { pos += prevViewHeight; } else if (i < prevIndex) { pos -= currViewHeight; } prevIndex = i; prevViewPos = currViewPos; prevViewHeight = currViewHeight; } catch (Exception e) { e.printStackTrace(); } finally { onScrollPositionChanged(pos); } } @Override public void onScrollStateChanged(AbsListView absListView, int i) {} public abstract void onScrollPositionChanged(int scrollYPosition); } 

我创build了自己的OnScrollListener,onScrollPositionChanged方法每次调用onScroll时都会被调用。 但是这个方法将有权访问表示ListView被滚动的数量的计算值。

要使用这个类,你可以将setOnClickListener设置为一个新的OnScrollPositionChangedListener,并覆盖onScrollPositionChanged方法。

如果你需要为其他东西使用onScroll方法,那么你也可以重写,但你需要调用super.onScroll来获得onScrollPositionChanged正常工作。

 myListView.setOnScrollListener( new OnScrollPositionChangedListener() { @Override public void onScroll(AbsListView v, int i, int vi, int n) { super.onScroll(v, i, vi, n); //Do your onScroll stuff } @Override public void onScrollPositionChanged(int scrollYPosition) { //Enjoy having access to the amount the ListView has scrolled } } ); 

我遇到了类似的问题,我想将垂直Seekbar放在ListView的当前滚动值。 所以我有我自己的解决scheme。

首先创build类

 public abstract class OnScrollPositionChangedListener implements AbsListView.OnScrollListener { int pos; public int viewHeight = 0; public int listHeight = 0; @Override public void onScroll(AbsListView v, int i, int vi, int n) { try { if(viewHeight==0) { viewHeight = v.getChildAt(0).getHeight(); listHeight = v.getHeight(); } pos = viewHeight * i; } catch (Exception e) { e.printStackTrace(); } finally { onScrollPositionChanged(pos); } } @Override public void onScrollStateChanged(AbsListView absListView, int i) {} public abstract void onScrollPositionChanged(int scrollYPosition); } 

然后像这样在主要活动中使用它。

 public class MainActivity extends AppCompatActivity { SeekBar seekBar; ListView listView; OnScrollPositionChangedListener onScrollPositionChangedListener = new OnScrollPositionChangedListener() { @Override public void onScroll(AbsListView v, int i, int vi, int n) { super.onScroll(v, i, vi, n); //Do your onScroll stuff } @Override public void onScrollPositionChanged(int scrollYPosition) { //Enjoy having access to the amount the ListView has scrolled seekBar.setProgress(scrollYPosition); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); seekBar = (SeekBar) findViewById(R.id.mySeekBar); listView = (ListView) findViewById(R.id.listView); final String[] values = new String[]{"Android List View", "Adapter implementation", "Simple List View In Android", "Create List View Android", "Android Example", }; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, values); listView.setAdapter(adapter); listView.setOnScrollListener(onScrollPositionChangedListener); seekBar.postDelayed(new Runnable() { @Override public void run() { seekBar.setMax((onScrollPositionChangedListener.viewHeight * values.length) - onScrollPositionChangedListener.listHeight); } }, 1000); seekBar.setEnabled(false); } } 

在应用程序中的Gradle

 compile 'com.h6ah4i.android.widget.verticalseekbar:verticalseekbar:0.7.0' 

在XML布局

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.centsol.charexamples.MainActivity"> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" android:fadeScrollbars="false" android:scrollbars="none" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true"> </ListView> <!-- This library requires pair of the VerticalSeekBar and VerticalSeekBarWrapper classes --> <com.h6ah4i.android.widget.verticalseekbar.VerticalSeekBarWrapper android:layout_width="wrap_content" android:layout_alignParentRight="true" android:layout_height="match_parent"> <com.h6ah4i.android.widget.verticalseekbar.VerticalSeekBar android:id="@+id/mySeekBar" android:layout_width="0dp" android:progressDrawable="@drawable/progress" android:thumb="@drawable/thumb" android:layout_height="0dp" android:splitTrack="false" app:seekBarRotation="CW90" /> <!-- Rotation: CW90 or CW270 --> </com.h6ah4i.android.widget.verticalseekbar.VerticalSeekBarWrapper> <View android:layout_width="1dp" android:visibility="visible" android:layout_alignParentRight="true" android:layout_marginTop="16dp" android:layout_marginRight="2.5dp" android:layout_marginBottom="16dp" android:background="@android:color/black" android:layout_height="match_parent" /> </RelativeLayout> 

背景xml

  <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="@android:color/transparent"/> </shape> 

填充xml

 <?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="@android:color/transparent" /> </shape> 

进步xml

 <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@android:id/background" android:drawable="@drawable/background"/> <item android:id="@android:id/progress"> <clip android:drawable="@drawable/fill" /> </item> </layer-list> 

拇指xml

 <?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" > <solid android:color="@android:color/holo_red_dark" /> <size android:height="5dp" android:width="5dp" /> </shape> 

除了@jaredpetker的回答。 ListView没有把所有的项目都保存在它的滚动条中,所以你只需要操作列表的“可见”部分。 当您向下滚动时,顶部项目将被移出并推送为新项目视图。 多数民众赞成在如何convertedView来自(这不是空的项目来填补,它是移出的项目是不可见的部分列表。所以你需要知道有多less项目之前,可见部分乘以ListItemHeight并添加headerHeight,这是如何你可以得到真正的绝对偏移在滚动。如果你没有头,位置0将是listItem,所以你可以简化absoluteY += pos*listItemHeight;

 public class CustomListView extends ListView { private int listItemHeight = 140; private int headerHeight = 200; public CustomListView(Context context) { super(context); } public CustomListView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public int computeVerticalScrollOffset() { final int y = super.computeVerticalScrollOffset(); int absoluteY = y; int pos = getFirstVisiblePosition(); if(pos > 0){ absoluteY += (pos-1)*listItemHeight+header‌​Height; } //use absoluteY return y; }