Android ListView текущее местоположение прокрутки Y пикселей
Я пытаюсь обнаружить, когда просмотр списка прокручивается за пределы определенного фиксированного порога в пикселях (на полпути через первый элемент). К сожалению listview getScrollY(), похоже, всегда возвращает 0 instad положения прокрутки. Есть ли способ получить фактическое местоположение прокрутки по пикселям?
Здесь код, который я пытался использовать, но, как сказано, возвращает 0.
getListView().setOnScrollListener(new AbsListView.OnScrollListener() {
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
Log.d("scroll", "scroll: " + getListView().getScrollY());
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == 0)
Log.d("scroll", "scrolling stopped");
}
});
Ответы
Ответ 1
Нет понятия прокрутки Y для ListView в Android просто потому, что общая высота содержимого неизвестна. Известна только высота отображаемого содержимого.
Однако можно получить текущую позицию /Y прокрутки видимого элемента с помощью следующего взлома:
getListView().getChildAt(0).getTop();
Ответ 2
Вы можете попробовать выполнить OnTouchListener
и переопределить его onTouch(View v, MotionEvent event)
и получить x и y с помощью event.getX()
и event.getY()
. Я только что создал демо для прокрутки в строке ListView, которая будет включать кнопку удаления для удаления определенного элемента из ListView. Вы можете проверить исходный код моего github как ListItemSwipe
.
Ответ 3
Код рефакторинга Malachiasz. Эта функция используется для динамической высоты строки.
Вызвать слушателя onScroll
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mCardsListView.getChildCount() > 0) {
int scrollY = getScrollY();
}
}
});
Функция getScrollY
private Dictionary<Integer, Integer> mListViewItemHeights = new Hashtable<Integer, Integer>();
private int getScrollY() {
View child = mCardsListView.getChildAt(0); //this is the first visible row
if (child == null) return 0;
int scrollY = -child.getTop();
mListViewItemHeights.put(mCardsListView.getFirstVisiblePosition(), child.getHeight());
for (int i = 0; i < mCardsListView.getFirstVisiblePosition(); ++i) {
Integer hei = mListViewItemHeights.get(i);
//Manual add hei each row into scrollY
if (hei != null)
scrollY += hei;
}
return scrollY;
}
Ответ 4
Может быть, это будет полезно для кого-то. Код предыдущего ответа не будет работать, если список прокручивается быстро. Потому что в этом случае firstVisiblePosition может быть изменен нерегулярно. В моем коде я не использую массив для хранения позиций
fun setOnTouchScrollListener(lv: AbsListView, onTouchScrollListener: (isDown: Boolean, offset: Int?, isScrollWorking: Boolean) -> Unit) {
var lastItemPosition: Int = -1
var lastItemTop: Int? = null
var lastItemHeight: Int? = null
var lastScrollState: Int? = AbsListView.OnScrollListener.SCROLL_STATE_IDLE
lv.setOnScrollListener(object : AbsListView.OnScrollListener {
override fun onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
val child = lv.getChildAt(0)
var offset: Int? = null
var isDown: Boolean? = if (firstVisibleItem == lastItemPosition || lastItemPosition == -1) null else firstVisibleItem > lastItemPosition
val dividerHeight = if (lv is ListView) lv.dividerHeight else 0
val columnCount = if (lv is GridView) lv.numColumns else 1
if (child != null) {
if (lastItemPosition != -1) {
when (firstVisibleItem - lastItemPosition) {
0 -> {
isDown = if (lastItemTop == child.top) null else lastItemTop!! > child.top
offset = Math.abs(lastItemTop!! - child.top)
}
columnCount -> offset = lastItemHeight!! + lastItemTop!! - child.top + dividerHeight
-columnCount -> offset = child.height + child.top - lastItemTop!! + dividerHeight
}
}
lastItemPosition = firstVisibleItem
lastItemHeight = child.height
lastItemTop = child.top
if (isDown != null && (offset == null || offset != 0)
&& lastScrollState != AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
onTouchScrollListener(isDown, offset, true)
}
}
}
override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
lastScrollState = scrollState
if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
onTouchScrollListener(true, 0, false)
lastItemPosition = -1
lastItemHeight = null
lastItemTop = null
}
}
})
}
Затем мы можем использовать, когда список просматривается вне порогового значения
private var lastThresholdOffset = 0
private var thresholdHeight = some value
setOnTouchScrollListener(listView) { isDown: Boolean, offset: Int?, isScrollWorking: Boolean ->
val offset = offset ?: if (isDown) 0 else thresholdHeight
lastThresholdOffset = if (isDown) Math.min(thresholdHeight, lastThresholdOffset + offset)
else Math.max(0, lastThresholdOffset - offset)
val result = lastThresholdOffset > thresholdHeight
}
isScrollWorking - может использоваться для анимации