在Android中,如何在尊重fling引起的加速度的同时实现listview的捕捉效果?

为了演示,我有一个显示数字列表的ListView。 我希望达到这样的效果:当用户滚动ListView并且滚动结束时,它将仅停止在某些位置,以便始终完全显示第一个可见项目。 我在下面附上了我的尝试代码。 当用户拖动滚动ListView时,它可以工作。 但是当它甩动时,正常加速度会中断,导致不自然的停止。 我的问题是,如何在实现相同效果的同时考虑到投掷加速度?

package com.example.snaptest; import android.content.Context; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends ActionBarActivity { private static class TestListViewAdapter extends BaseAdapter { private Context mContext; public TestListViewAdapter(Context context) { mContext = context; } @Override public int getCount() { return 100; } @Override public Object getItem(int position) { return Integer.toString(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView textView = new TextView(mContext); textView.setText(Integer.toString(position)); AbsListView.LayoutParams params = new AbsListView.LayoutParams(ViewGroup.LayoutParams .MATCH_PARENT, 180); textView.setLayoutParams(params); return textView; } } private static class TestListView extends ListView { public TestListView(Context context) { super(context); } @Override public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { View itemView = getChildAt(0); int top = Math.abs(itemView.getTop()); // top is a negative value int bottom = Math.abs(itemView.getBottom()); if (top >= bottom){ smoothScrollToPositionFromTop (getFirstVisiblePosition() + 1, 0); } else { smoothScrollToPositionFromTop (getFirstVisiblePosition(), 0); } } return super.onTouchEvent(ev); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TestListView listView = new TestListView(this); listView.setAdapter(new TestListViewAdapter(this)); setContentView(listView); } } 

我会尝试使用OnScrollListener而不是扩展ListView

像这样的东西:

 listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == AbsListView.SCROLL_STATE_IDLE) { // snap the listview according to the top/bottom items' visibility } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } });