Я хотел бы получить точную позицию пикселя прокрутки ListView. И нет, я не имею в виду первую видимую позицию.Android получает точную позицию прокрутки в ListView
Есть ли способ достичь этого?
Я хотел бы получить точную позицию пикселя прокрутки ListView. И нет, я не имею в виду первую видимую позицию.Android получает точную позицию прокрутки в ListView
Есть ли способ достичь этого?
Хорошо, я нашел обходной путь, используя следующий код:
View c = listview.getChildAt(0);
int scrolly = -c.getTop() + listview.getFirstVisiblePosition() * c.getHeight();
Как это работает, он принимает фактическое смещение первого видимого элемента списка и вычисляет, как далеко он находится от верхней части чтобы определить, насколько мы «прокручиваем» представление, поэтому теперь, когда мы знаем, что мы можем рассчитать остальное, используя обычный метод getFirstVisiblePosition.
Ответ 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;
}
Я смущен этим решением. Когда вы называете этот метод? Вы сохраняете только одно значение в словаре? –
Нет, не один. Значение listView.getFirstVisiblePosition() изменяется при прокрутке вниз по списку. И как только верхние строки исчезают наверху, у меня нет доступа к ним, чтобы проверить их высоту. – Maria
Конечно, это работает только в том случае, если пользователь вручную прокручивал все элементы списка. Если вы программно устанавливаете позицию списка, это не сработает. –
Если кто-то нашел в Google, ища способ отслеживания относительно смещения прокрутки в OnScrollListener - то есть, изменение Y с момента последнего вызова к слушателю - here's a Gist showing how to calculate that.
Я почти попытаюсь вычислить, что positeom listview. Надеюсь, это сработает, я постараюсь завтра. –
[Здесь] (http://stackoverflow.com/questions/12727594/android-listview-current-scroll-location-y-pixels/35594825#35594825) как его использовать – Sarasranglt
Простейшей идеей, которую я мог придумать, было расширить ListView и выставить «computeVerticalScrollOffset», который по умолчанию защищен, а затем использовать «com.your.package.CustomListView» в ваших xml-макетах.
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();
}
}
Это хороший трюк, но, к сожалению, результат находится в некоторых странных единицах, например в то время как заголовок частично виден, 'computeVerticalScrollOffset()' сообщает проценты этого разворота заголовка. Когда я больше прокручиваю, результат монотонно возрастает, но я не уверен, как это можно перевести в пикселях из (виртуального) вершины первого заголовка. –
computeVerticalScrollOffset относительно первого элемента в «видимом» списке. Вам нужно понять, как ListView вычисляет его. Вы помните getView (int position, View convertView, ViewGroup parent) в Adapter? старый элемент сверху списка выставляется и преобразуется в элемент внизу и наоборот. Вы можете использовать getFirstVisiblePosition(). '' ' y = super.computeVerticalScrollOffset(); if (listView.getFirstVisiblePosition()> 0) { y + = (listView.getFirstVisiblePosition() - 1) * listItemHeight + headerHeight; }} '' ' –
добавлен полный пример как новый ответ –
Сначала объявите переменную 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);
I использовали после настройки мой адаптер, отлично работает для меня ..
Это не отвечает на вопрос ОП, но это простое решение для установки положения прокрутки списка в зависимости от его предыдущей позиции, независимо от размера ячейки. – Grux
Я знаю, что опаздываю на пар но я решил поделиться своим решением этой проблемы. У меня есть 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 где метод onScrollPositionChanged будет вызываться каждый раз, когда OnScroll будет вызываться. Но этот метод будет иметь доступ к вычисленному значению, представляющему сумму, которую прокрутила ListView.
Чтобы использовать этот класс, вы можете установитьOnClickListener в новый 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
}
}
);
Спасибо! У меня была такая же идея, и я сделал копию вашего образца. Но для меня это не работает точно, у меня есть смещение, когда я делаю жесткий тест очень быстро. – fingerup
я столкнулся с подобной проблемой, что я хотел поместить Vertical SeekBar по текущим прокручивать значения ListView. Поэтому у меня есть собственное решение, подобное этому.
Первый Создание класса
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);
}
}
в App 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 не удерживает все элементы в своем прокрутке, поэтому вам нужно использовать только «видимую» часть списка. Когда вы прокручиваете вниз, верхние элементы сдвигаются и отображаются как новые элементы. То, как происходит преобразованиеView (это не пустой элемент для заполнения, это сдвинутый элемент, который не входит в «видимую» часть списка. Поэтому вам нужно знать, сколько элементов было перед видимой частью, умножить их на ListItemHeight и добавить headerHeight, thes how вы можете получить реальное абсолютное смещение в свитке Если и получил не заголовок, позиция 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;
}
, как вы при условии, решает другую проблему -. Как восстановить положение ListView, в то время как моя проблема заключается в том, как получить фактическое значение положения прокрутки. – saarraz1