activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.harvic.scrollview_scroller.MainActivity" >
<com.harvic.scrollview_scroller.MyListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
item_layout.xml
<?xml version="1.0" encoding="utf-8"?
> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/lin_root" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="120dp"> <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FF83FA" android:gravity="center" android:textSize="25dp" /> <TextView android:id="@+id/del" android:layout_width="200dp" android:layout_height="fill_parent" android:background="#EEEEE0" android:text="删除" android:textSize="25dp" android:textColor="#ffffff" android:gravity="center" /> </LinearLayout>
MainActivitypackage com.harvic.scrollview_scroller;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import com.harvic.scrollview_scroller.MergeListAdapter.DataHolder;
public class MainActivity extends Activity implements View.OnClickListener {
private MyListView listView;
private MergeListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (MyListView)findViewById(R.id.listview);
final List<DataHolder> items = new ArrayList<DataHolder>();
for(int i=0;i<20;i++){
DataHolder item = new DataHolder();
item.title = "第"+i+"项";
items.add(item);
}
adapter = new MergeListAdapter(this,items,this);
listView.setAdapter(adapter);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.del){
int position = listView.getPositionForView(v);
adapter.removeItem(position);
}
}
}
MergeListAdapter
package com.harvic.scrollview_scroller;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by enwei.zew on 2015/4/16.
*/
public class MergeListAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
private List<DataHolder> mDataList = new ArrayList<DataHolder>();
private View.OnClickListener mDelClickListener;
public MergeListAdapter(Context context, List<DataHolder> dataList, View.OnClickListener delClickListener) {
mContext = context;
mInflater = LayoutInflater.from(context);
if (dataList != null && dataList.size() > 0) {
mDataList.addAll(dataList);
}
mDelClickListener = delClickListener;
}
public void removeItem(int position) {
mDataList.remove(position);
notifyDataSetChanged();
}
public void addItem(DataHolder item) {
mDataList.add(item);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mDataList.size();
}
@Override
public Object getItem(int position) {
return mDataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null || convertView.getTag() == null) {
convertView = mInflater.inflate(R.layout.item_layout, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
DataHolder item = mDataList.get(position);
holder.title.setText(item.title);
item.rootView = (LinearLayout) convertView.findViewById(R.id.lin_root);
item.rootView.scrollTo(0, 0);
//点击删除实现方法二:交由外部处理:
TextView delTv = (TextView) convertView.findViewById(R.id.del);
delTv.setOnClickListener(mDelClickListener);
return convertView;
}
private static class ViewHolder {
public TextView title;
}
public static class DataHolder {
public String title;
public LinearLayout rootView;
}
}
MyListView
package com.harvic.scrollview_scroller;
import com.harvic.scrollview_scroller.MergeListAdapter.DataHolder;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Scroller;
public class MyListView extends ListView {
// 每一个条目的容器控件
private LinearLayout itemRoot;
// 上次手指的x轴坐标
private int mlastX = 0;
// 删除控件的最大宽度
private final int MAX_WIDTH = 200;
private Context mContext;
// scrollTo()是没有办法加入运动的时间长度的,所以为了弥补这个问题,google就新增了一个类Scroller!
private Scroller mScroller; public MyListView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; // 创建具有插值器的构造方法 mScroller = new Scroller(context, new LinearInterpolator(context, null)); } @Override public boolean onTouchEvent(MotionEvent event) { int maxLength = dipToPx(mContext, MAX_WIDTH); // 获取手势操作触发的xy轴坐标值 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { // 我们想知道当前点击了哪一行 int position = pointToPosition(x, y); if (position != INVALID_POSITION) { // 获取点击的item控件的id值 DataHolder data = (DataHolder) getItemAtPosition(position); itemRoot = data.rootView; } } break; case MotionEvent.ACTION_MOVE: { // 获取item的容器控件在x轴偏移量 int scrollX = itemRoot.getScrollX(); // 实时获取最新的偏移量 int newScrollX = scrollX + mlastX - x; // 假设手势向右边滑动,可能<0 if (newScrollX < 0) { newScrollX = 0; } else if (newScrollX > maxLength) { newScrollX = maxLength; } itemRoot.scrollTo(newScrollX, 0); } break; case MotionEvent.ACTION_UP: { int scrollX = itemRoot.getScrollX(); int newScrollX = scrollX + mlastX - x; if (scrollX > maxLength / 2) { newScrollX = maxLength; } else { newScrollX = 0; } // startScroll(int startX, int startY, int dx, int dy) /** * startX:開始移动的X坐标 startY開始移动的Y坐标 * dx:沿X轴移动距离,可正可负,为正时。子控件向左移动;为负时,子控件向右移动 * dy:沿Y轴移动距离,相同,为正时,子控件向上移动;为负时。子控件向下移动 duration:整个移动过程,所耗费时长 */ mScroller.startScroll(scrollX, 0, newScrollX - scrollX, 0); invalidate(); } break; } mlastX = x; return super.onTouchEvent(event); } private int dipToPx(Context context, int dip) { return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f); } /** * computeScroll()函数。不是Scroller的函数,而是VIEW的函数, * 当调用invaidate或者postInvalidate重绘时就会调用computeScroll() 来重绘与scroller有关的View部分, */ @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { itemRoot.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); } invalidate(); } }
************************************************升级********************************************
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.harvic.scrollviewultimate.MainActivity" >
<com.harvic.scrollviewultimate.MyListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
item_layout.xml
<?xml version="1.0" encoding="utf-8"?
> <com.harvic.scrollviewultimate.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/lin_root" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="120dp"> <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#0000ff" android:gravity="center" android:textSize="25dp" /> <TextView android:id="@+id/del" android:layout_width="200dp" android:layout_height="fill_parent" android:background="#ffff00" android:text="删除" android:textSize="25dp" android:textColor="#ffffff" android:gravity="center" /> </com.harvic.scrollviewultimate.MyLinearLayout>
MainActivity
package com.harvic.scrollviewultimate;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import com.harvic.scrollviewultimate.MergeListAdapter.DataHolder;
public class MainActivity extends Activity implements View.OnClickListener,MyLinearLayout.OnScrollListener{
private MyListView listView;
private MergeListAdapter adapter;
private MyLinearLayout mLastScrollView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (MyListView)findViewById(R.id.listview);
final List<DataHolder> items = new ArrayList<DataHolder>();
for(int i=0;i<20;i++){
DataHolder item = new DataHolder();
item.title = "第"+i+"项";
items.add(item);
}
adapter = new MergeListAdapter(this,items,this,this);
listView.setAdapter(adapter);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.del){
int position = listView.getPositionForView(v);
adapter.removeItem(position);
}
}
@Override
public void OnScroll(MyLinearLayout view) {
if (mLastScrollView != null){
mLastScrollView.smoothScrollTo(0,0);
}
mLastScrollView = view;
}
}
MyListView
package com.harvic.scrollviewultimate;
import com.harvic.scrollviewultimate.MergeListAdapter.DataHolder;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView;
public class MyListView extends ListView {
private MyLinearLayout mCurView;
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
int position = pointToPosition(x, y);
if (position != INVALID_POSITION) {
DataHolder data = (DataHolder) getItemAtPosition(position);
mCurView = data.rootView;
}
}
break;
default:
break;
}
if (mCurView != null){
mCurView.disPatchTouchEvent(event);
}
return super.onTouchEvent(event);
}
}
MergeListAdapter
package com.harvic.scrollviewultimate;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MergeListAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
private List<DataHolder> mDataList = new ArrayList<DataHolder>();
private View.OnClickListener mDelClickListener;
private MyLinearLayout.OnScrollListener mScrollListener;
public MergeListAdapter(Context context, List<DataHolder> dataList, View.OnClickListener delClickListener,MyLinearLayout.OnScrollListener listener) {
mContext = context;
mInflater = LayoutInflater.from(context);
if (dataList != null && dataList.size() > 0) {
mDataList.addAll(dataList);
}
mDelClickListener = delClickListener;
mScrollListener = listener;
}
public void removeItem(int position) {
mDataList.remove(position);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mDataList.size();
}
@Override
public Object getItem(int position) {
return mDataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null || convertView.getTag() == null) {
convertView = mInflater.inflate(R.layout.item_layout, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
DataHolder item = mDataList.get(position);
holder.title.setText(item.title);
item.rootView = (MyLinearLayout) convertView.findViewById(R.id.lin_root);
item.rootView.scrollTo(0, 0);
item.rootView.setOnScrollListener(mScrollListener);
//点击删除实现方法二:交由外部处理:
TextView delTv = (TextView) convertView.findViewById(R.id.del);
delTv.setOnClickListener(mDelClickListener);
return convertView;
}
private static class ViewHolder {
public TextView title;
}
public static class DataHolder {
public String title;
public MyLinearLayout rootView;
}
}
MyLinearLayout
package com.harvic.scrollviewultimate;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;
/**
* Created by enwei.zew on 2015/4/28.
*/
public class MyLinearLayout extends LinearLayout {
private int mlastX = 0;
private final int MAX_WIDTH = 200;
private Context mContext;
private Scroller mScroller;
private OnScrollListener mScrollListener;
public static interface OnScrollListener {
public void OnScroll(MyLinearLayout view);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
mScroller = new Scroller(context, new LinearInterpolator(context, null));
}
public void disPatchTouchEvent(MotionEvent event) {
int maxLength = dipToPx(mContext, MAX_WIDTH);
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
}
break;
case MotionEvent.ACTION_MOVE: {
int scrollX = this.getScrollX();
int newScrollX = scrollX + mlastX - x;
if (newScrollX < 0) {
newScrollX = 0;
} else if (newScrollX > maxLength) {
newScrollX = maxLength;
}
this.scrollTo(newScrollX, 0);
}
break;
case MotionEvent.ACTION_UP: {
int scrollX = this.getScrollX();
int newScrollX = scrollX + mlastX - x;
if (scrollX > maxLength / 2) {
newScrollX = maxLength;
mScrollListener.OnScroll(this);
} else {
newScrollX = 0;
}
mScroller.startScroll(scrollX, 0, newScrollX - scrollX, 0);
invalidate();
}
break;
}
mlastX = x;
}
public void setOnScrollListener(OnScrollListener scrollListener) {
mScrollListener = scrollListener;
}
public void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
mScroller.startScroll(scrollX, 0, delta, 0);
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
this.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
}
invalidate();
}
private int dipToPx(Context context, int dip) {
return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f);
}
}