次の要件があります。
シナリオで前のページと次のページの両方が使用できることを考慮して、次のコードが追加されました。
if(prevPageNo > 0){
mListViewActual.setOnScrollListener(this);
}
if(nextPageNo > 0){
mListViewActual.setOnScrollListener(this);
}
次の方法でスクロールアップおよびスクロールダウンを検出するには、どのような条件を設定する必要がありますか。
アクション:スクロールアップとスクロールダウンが検出された後、前のページnoまたは次のページnoのいずれかでサービスが呼び出され、リストビューに入力されるアイテムを取得します。
任意の入力が役立ちます。
以下のリンクをたどりましたが、正しいスクロールアップ/スクロールダウンアクションが返されません。
setOnScrollListenerを使用してみて、scrollStateでonScrollStateChangedを実装してください
setOnScrollListener(new OnScrollListener(){
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
final ListView lw = getListView();
if(scrollState == 0)
Log.i("a", "scrolling stopped...");
if (view.getId() == lw.getId()) {
final int currentFirstVisibleItem = lw.getFirstVisiblePosition();
if (currentFirstVisibleItem > mLastFirstVisibleItem) {
mIsScrollingUp = false;
Log.i("a", "scrolling down...");
} else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
mIsScrollingUp = true;
Log.i("a", "scrolling up...");
}
mLastFirstVisibleItem = currentFirstVisibleItem;
}
}
});
上に示したソリューションのいくつかからの作業修正バージョンがあります。
別のクラスListViewを追加します。
package com.example.view;
import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.View;
import Android.widget.AbsListView;
public class ListView extends Android.widget.ListView {
private OnScrollListener onScrollListener;
private OnDetectScrollListener onDetectScrollListener;
public ListView(Context context) {
super(context);
onCreate(context, null, null);
}
public ListView(Context context, AttributeSet attrs) {
super(context, attrs);
onCreate(context, attrs, null);
}
public ListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
onCreate(context, attrs, defStyle);
}
@SuppressWarnings("UnusedParameters")
private void onCreate(Context context, AttributeSet attrs, Integer defStyle) {
setListeners();
}
private void setListeners() {
super.setOnScrollListener(new OnScrollListener() {
private int oldTop;
private int oldFirstVisibleItem;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (onScrollListener != null) {
onScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (onScrollListener != null) {
onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
if (onDetectScrollListener != null) {
onDetectedListScroll(view, firstVisibleItem);
}
}
private void onDetectedListScroll(AbsListView absListView, int firstVisibleItem) {
View view = absListView.getChildAt(0);
int top = (view == null) ? 0 : view.getTop();
if (firstVisibleItem == oldFirstVisibleItem) {
if (top > oldTop) {
onDetectScrollListener.onUpScrolling();
} else if (top < oldTop) {
onDetectScrollListener.onDownScrolling();
}
} else {
if (firstVisibleItem < oldFirstVisibleItem) {
onDetectScrollListener.onUpScrolling();
} else {
onDetectScrollListener.onDownScrolling();
}
}
oldTop = top;
oldFirstVisibleItem = firstVisibleItem;
}
});
}
@Override
public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}
public void setOnDetectScrollListener(OnDetectScrollListener onDetectScrollListener) {
this.onDetectScrollListener = onDetectScrollListener;
}
}
そしてインターフェース:
public interface OnDetectScrollListener {
void onUpScrolling();
void onDownScrolling();
}
最後に使用方法:
com.example.view.ListView listView = (com.example.view.ListView) findViewById(R.id.list);
listView.setOnDetectScrollListener(new OnDetectScrollListener() {
@Override
public void onUpScrolling() {
/* do something */
}
@Override
public void onDownScrolling() {
/* do something */
}
});
XMLレイアウトで:
<com.example.view.ListView
Android:id="@+id/list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"/>
これは私の最初のトピックです、私を厳しく判断しないでください。 =)
これは簡単な実装です:
lv.setOnScrollListener(new OnScrollListener() {
private int mLastFirstVisibleItem;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(mLastFirstVisibleItem<firstVisibleItem)
{
Log.i("SCROLLING DOWN","TRUE");
}
if(mLastFirstVisibleItem>firstVisibleItem)
{
Log.i("SCROLLING UP","TRUE");
}
mLastFirstVisibleItem=firstVisibleItem;
}
});
さらに精度が必要な場合は、このカスタムListViewクラスを使用できます。
import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.View;
import Android.widget.AbsListView;
import Android.widget.ListView;
/**
* Created by root on 26/05/15.
*/
public class ScrollInterfacedListView extends ListView {
private OnScrollListener onScrollListener;
private OnDetectScrollListener onDetectScrollListener;
public ScrollInterfacedListView(Context context) {
super(context);
onCreate(context, null, null);
}
public ScrollInterfacedListView(Context context, AttributeSet attrs) {
super(context, attrs);
onCreate(context, attrs, null);
}
public ScrollInterfacedListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
onCreate(context, attrs, defStyle);
}
@SuppressWarnings("UnusedParameters")
private void onCreate(Context context, AttributeSet attrs, Integer defStyle) {
setListeners();
}
private void setListeners() {
super.setOnScrollListener(new OnScrollListener() {
private int oldTop;
private int oldFirstVisibleItem;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (onScrollListener != null) {
onScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (onScrollListener != null) {
onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
if (onDetectScrollListener != null) {
onDetectedListScroll(view, firstVisibleItem);
}
}
private void onDetectedListScroll(AbsListView absListView, int firstVisibleItem) {
View view = absListView.getChildAt(0);
int top = (view == null) ? 0 : view.getTop();
if (firstVisibleItem == oldFirstVisibleItem) {
if (top > oldTop) {
onDetectScrollListener.onUpScrolling();
} else if (top < oldTop) {
onDetectScrollListener.onDownScrolling();
}
} else {
if (firstVisibleItem < oldFirstVisibleItem) {
onDetectScrollListener.onUpScrolling();
} else {
onDetectScrollListener.onDownScrolling();
}
}
oldTop = top;
oldFirstVisibleItem = firstVisibleItem;
}
});
}
@Override
public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}
public void setOnDetectScrollListener(OnDetectScrollListener onDetectScrollListener) {
this.onDetectScrollListener = onDetectScrollListener;
}
public interface OnDetectScrollListener {
void onUpScrolling();
void onDownScrolling();
}
}
使用例:(layout.xmlにXmlタグとして追加することを忘れないでください)
scrollInterfacedListView.setOnDetectScrollListener(new ScrollInterfacedListView.OnDetectScrollListener() {
@Override
public void onUpScrolling() {
//Do your thing
}
@Override
public void onDownScrolling() {
//Do your thing
}
});
すべてのメソッドがポストされると、ユーザーが最初の要素から上にスクロールするのか、最後から下にスクロールするのかを認識するのに問題があります。スクロールの上下を検出する別のアプローチを次に示します。
listView.setOnTouchListener(new View.OnTouchListener() {
float height;
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
float height = event.getY();
if(action == MotionEvent.ACTION_DOWN){
this.height = height;
}else if(action == MotionEvent.ACTION_UP){
if(this.height < height){
Log.v(TAG, "Scrolled up");
}else if(this.height > height){
Log.v(TAG, "Scrolled down");
}
}
return false;
}
});
ListView listView = getListView();
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
view.setOnTouchListener(new OnTouchListener() {
private float mInitialX;
private float mInitialY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialX = event.getX();
mInitialY = event.getY();
return true;
case MotionEvent.ACTION_MOVE:
final float x = event.getX();
final float y = event.getY();
final float yDiff = y - mInitialY;
if (yDiff > 0.0) {
Log.d(tag, "SCROLL DOWN");
scrollDown = true;
break;
} else if (yDiff < 0.0) {
Log.d(tag, "SCROLL up");
scrollDown = true;
break;
}
break;
}
return false;
}
});
私のソリューションは完全に機能し、スクロール方向ごとに正確な値を提供します。 distanceFromFirstCellToTop
には、最初のセルから親ビューの最上部までの正確な距離が含まれます。この値をpreviousDistanceFromFirstCellToTop
に保存し、スクロールしながら新しい値と比較します。低い場合は上にスクロールし、そうでない場合は下にスクロールします。
private int previousDistanceFromFirstCellToTop;
listview.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View firstCell = listview.getChildAt(0);
int distanceFromFirstCellToTop = listview.getFirstVisiblePosition() * firstCell.getHeight() - firstCell.getTop();
if(distanceFromFirstCellToTop < previousDistanceFromFirstCellToTop)
{
//Scroll Up
}
else if(distanceFromFirstCellToTop > previousDistanceFromFirstCellToTop)
{
//Scroll Down
}
previousDistanceFromFirstCellToTop = distanceFromFirstCellToTop;
}
});
Xamarin開発者向けのソリューションは次のとおりです。
注:UIスレッドで実行することを忘れないでください
listView.Scroll += (o, e) =>
{
View firstCell = listView.GetChildAt(0);
int distanceFromFirstCellToTop = listView.FirstVisiblePosition * firstCell.Height - firstCell.Top;
if (distanceFromFirstCellToTop < previousDistanceFromFirstCellToTop)
{
//Scroll Up
}
else if (distanceFromFirstCellToTop > previousDistanceFromFirstCellToTop)
{
//Scroll Down
}
previousDistanceFromFirstCellToTop = distanceFromFirstCellToTop;
};
より大きな要素でのスクロールも検出するには、onTouch Listenerを好みます。
listview.setOnTouchListener(new View.OnTouchListener() {
int scrollEventListSize = 5;
float lastY;
// Used to correct for occasions when user scrolls down(/up) but the onTouchListener detects it incorrectly. We will store detected up-/down-scrolls with -1/1 in this list and evaluate later which occured more often
List<Integer> downScrolledEventsHappened;
@Override
public boolean onTouch(View v, MotionEvent event) {
float diff = 0;
if(event.getAction() == event.ACTION_DOWN){
lastY = event.getY();
downScrolledEventsHappened = new LinkedList<Integer>();
}
else if(event.getAction() == event.ACTION_MOVE){
diff = event.getY() - lastY;
lastY = event.getY();
if(diff>0)
downScrolledEventsHappened.add(1);
else
downScrolledEventsHappened.add(-1);
//List needs to be filled with some events, will happen very quickly
if(downScrolledEventsHappened.size() == scrollEventListSize+1){
downScrolledEventsHappened.remove(0);
int res=0;
for(int i=0; i<downScrolledEventsHappened.size(); i++){
res+=downScrolledEventsHappened.get(i);
}
if (res > 0)
Log.i("INFO", "Scrolled up");
else
Log.i("INFO", "Scrolled down");
}
}
return false; // don't interrupt the event-chain
}
});
このはるかに単純なソリューションを使用しました。
setOnScrollListener( new OnScrollListener()
{
private int mInitialScroll = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount)
{
int scrolledOffset = computeVerticalScrollOffset();
boolean scrollUp = scrolledOffset > mInitialScroll;
mInitialScroll = scrolledOffset;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
リストビューにスクロールリスナーを設定するだけです。
ヘッダーまたはフッターがある場合は、表示カウントも確認する必要があります。増加する場合、下にスクロールしていることを意味します。 (ヘッダーの代わりにフッターがある場合は逆にします)
リストビューにヘッダーまたはフッターがない場合は、表示されているアイテム数をチェックする行を削除できます。
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mLastFirstVisibleItem > firstVisibleItem) {
Log.e(getClass().toString(), "scrolling up");
} else if (mLastFirstVisibleItem < firstVisibleItem) {
Log.e(getClass().toString(), "scrolling down");
} else if (mLastVisibleItemCount < visibleItemCount) {
Log.e(getClass().toString(), "scrolling down");
} else if (mLastVisibleItemCount > visibleItemCount) {
Log.e(getClass().toString(), "scrolling up");
}
mLastFirstVisibleItem = firstVisibleItem;
mLastVisibleItemCount = visibleItemCount;
}
public void onScrollStateChanged(AbsListView listView, int scrollState) {
}
});
そして、この変数を持っています
int mLastFirstVisibleItem;
int mLastVisibleItemCount;
FirstVisibleItemを保存し、次のonScrollチェックで、新しいfirstVisibleItemが前のものよりも小さいか大きいかを確認します。
擬似コードの例(テストされていません):
int lastVisibleItem = 0;
boolean isScrollingDown = false;
void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > lastVisibleItem) {
isScrollingDown = true;
}
else {
isScrollingDown = false;
}
lastVisibleItem = firstVisibleItem;
}
何らかの理由でAndroidのドキュメントはこれをカバーしておらず、使用されているメソッドはドキュメント内でもありません...見つけるのに時間がかかりました。
スクロールが上部にあるかどうかを検出するには、これを使用します。
public boolean checkAtTop()
{
if(listView.getChildCount() == 0) return true;
return listView.getChildAt(0).getTop() == 0;
}
これにより、スクローラーが上部にあるかどうかが確認されます。今、一番下にそれをするために、あなたが持っている子供の数をそれに渡して、その数に対してチェックする必要があります。一度に画面に表示される人数を把握し、それを子供の数から差し引く必要があるかもしれません。私はそれをする必要がなかった。お役に立てれば
Android listviewのスクロールアップ/ダウンを検出する簡単な方法
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount){
if(prevVisibleItem != firstVisibleItem){
if(prevVisibleItem < firstVisibleItem)
//ScrollDown
else
//ScrollUp
prevVisibleItem = firstVisibleItem;
}
忘れないで
yourListView.setOnScrollListener(yourScrollListener);
リストビューでスクロールの上下を検出するトリックは、ListViewのOnScrollListenerのonScroll関数でこの関数を呼び出すだけです。
private int oldFirstVisibleItem = -1;
private protected int oldTop = -1;
// you can change this value (pixel)
private static final int MAX_SCROLL_DIFF = 5;
private void calculateListScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem == oldFirstVisibleItem) {
int top = view.getChildAt(0).getTop();
// range between new top and old top must greater than MAX_SCROLL_DIFF
if (top > oldTop && Math.abs(top - oldTop) > MAX_SCROLL_DIFF) {
// scroll up
} else if (top < oldTop && Math.abs(top - oldTop) > MAX_SCROLL_DIFF) {
// scroll down
}
oldTop = top;
} else {
View child = view.getChildAt(0);
if (child != null) {
oldFirstVisibleItem = firstVisibleItem;
oldTop = child.getTop();
}
}
}
ListViewのセルサイズが大きいいくつかの例を使用して問題が発生しました。それで、あなたの指のわずかな動きを検出する私の問題の解決策を見つけました。私は可能な限り最小限に単純化しており、次のとおりです。
private int oldScrolly;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View view = absListView.getChildAt(0);
int scrolly = (view == null) ? 0 : -view.getTop() + absListView.getFirstVisiblePosition() * view.getHeight();
int margin = 10;
Log.e(TAG, "Scroll y: " + scrolly + " - Item: " + firstVisibleItem);
if (scrolly > oldScrolly + margin) {
Log.d(TAG, "SCROLL_UP");
oldScrolly = scrolly;
} else if (scrolly < oldScrolly - margin) {
Log.d(TAG, "SCROLL_DOWN");
oldScrolly = scrolly;
}
}
});
PD:MARGINを使用して、そのマージンを満たすまでスクロールを検出しません。これにより、ビューを表示または非表示にするときの問題を回避し、ビューの点滅を回避します。
私が最初に試すことは次のとおりです。
1)次のメソッドを使用してインターフェイスを作成します(OnScrollTopOrBottomListenerと呼びます)。
void onScrollTop();
void onScrollBottom();
2)リストのアダプターに、作成したインターフェイスとして入力されたメンバーインスタンスを追加し、セッターとゲッターを提供します。
3)アダプターのgetView()実装で、positionパラメーターが0またはgetCount()-1であるかどうかを確認します。OnScrollTopOrBottomListenerインスタンスがnullでないことも確認します。
4)位置が0の場合、onScrollTopOrBottomListener.onScrollTop()を呼び出します。位置がgetCount()-1の場合、onScrollTopOrBottomListener.onScrollBottom()を呼び出します。
5)OnScrollTopOrBottomListenerの実装で、適切なメソッドを呼び出して目的のデータを取得します。
それが何らかの形で役立つことを願っています。
-ブランドン