我想获得ListView滚动的精确像素位置。 不,我不是指第一个可见的位置。
有没有办法实现这个目标?
答案 0 :(得分:79)
好的,我找到了一种解决方法,使用以下代码:
View c = listview.getChildAt(0);
int scrolly = -c.getTop() + listview.getFirstVisiblePosition() * c.getHeight();
它的工作方式是它获取第一个可见列表项的实际偏移量,并计算它与视图顶部的距离,以确定我们“滚动到”视图中的数量,所以现在我们知道了我们可以使用常规的getFirstVisiblePosition方法计算其余部分。
答案 1 :(得分:29)
Saarraz1的答案只有在列表视图中的所有行具有相同高度并且没有标题(或者它与行的高度相同)时才有效。
请注意,一旦行消失在屏幕顶部,您就无法访问它们,因为您将无法跟踪它们的高度。这就是为什么你需要保存这些高度(或所有的累积高度)。我的解决方案需要保持每个索引的高度字典(假设在第一次滚动到顶部时显示列表)。
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;
}
答案 2 :(得分:20)
我能想到的最简单的想法是扩展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();
}
}
答案 3 :(得分:9)
如果其他人在Google中发现这一点,同时寻找一种方法来跟踪OnScrollListener中的 relative 滚动偏移量 - 也就是说,自上次调用侦听器后更改为Y - here's a Gist showing how to calculate that
答案 4 :(得分:6)
首先声明你的int变量以保持位置。
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当前位置
listView.setSelection(position);
我在安装后使用了我的适配器,对我来说很好..
答案 5 :(得分:2)
我知道我迟到了,但我想分享我对这个问题的解决方案。我有一个ListView,我试图找到我滚动了多少,以便相对于它滚动其他东西,并导致视差效果。这是我的解决方案:
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);
}
我创建了自己的OnScrollListener,每次调用onScroll时都会调用onScrollPositionChanged方法。但是,此方法可以访问表示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
}
}
);
答案 6 :(得分:1)
我遇到了类似的问题,我想将垂直搜索栏放在 ListView 的当前滚动值上。所以我有这样的解决方案。
首先创建班级
string name = ...
int regionId = ...
var customers = connection.Query<Customer>(
"select * from Customers where Name = @name and RegionId = @regionId",
new { name, regionId }).AsList();
然后在主要活动中使用它。
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);
}
App Gradle中的
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);
}
}
在XML布局中
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>
thumb 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>
答案 7 :(得分:1)
除了@jaredpetker回答。
ListView没有保存其滚动条中的所有项目,因此您只需要操作&#34;可见&#34;列表的一部分。当您向下滚动时,顶部项目会被移出并作为新项目视图推送。这就是转换视图是如何来的(它不是空的项目来填充,它的移动项目是&#34;可见&#34;列表的一部分。所以你需要知道有多少项目是在可见部分与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+headerHeight;
}
//use absoluteY
return y;
}