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

时间:2015-03-12 20:40:54

标签: java android listview android-listview android-animation

为了演示,我有一个显示数字列表的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);
    }

}

1 个答案:

答案 0 :(得分:1)

我会尝试使用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) {
  }
});