For demonstration, I have a ListView displaying a list of numbers. I would like to achieve the effect that when the user scrolls the ListView and the scrolling ends, it will only stop at certain positions so that the first visible item is always shown completely. I've attached my attempted code below. It works when users drag to scroll the ListView. But when there's fling, the normal acceleration is interrupted, causing an unnatural stop. My question is, how can I take acceleration caused by fling into account while achieving the same effect?
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);
}
}
I would try with an OnScrollListener
rather than extending ListView
.
Something like this:
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) {
}
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.