SelectHelper 支持单击选中 双击选中 多选 连续多选

public class SelectHelper {
	private Context context;
	private AbsListView mObj;
	private int listCount = -1;

	public void setListCount(int listCount) {
		this.listCount = listCount;
	}

	public SelectHelper(Context context, AttributeSet attrs, AbsListView obj) {
		this.context = context;
		this.mObj = obj;
		mode = context.getResources().getStringArray(R.array.select_item);
		clickR = new Runnable() {

			@Override
			public void run() {
				onSingleTap(mLastTouchPosition);
			}
		};
		longPressR = new Runnable() {

			@Override
			public void run() {
				isClick = false;
				onLongPress();
			}
		};
		mHandler = new Handler();
		longPressTimeout = ViewConfiguration.getLongPressTimeout();
		slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

	}

	private Handler mHandler;
	private int longPressTimeout;
	private int doubleTapTimeout = 250;
	private int slop;
	private Runnable clickR;
	private Runnable longPressR;

	private Context getContext() {
		return context;
	}

	private int mLastTouchPosition = -1;
	private int mFirstSelect = -1;
	private long first = 0;
	private int mDownX;
	private int mDownY;
	private boolean isClick;
	public void onTouchEvent(MotionEvent ev, int motionPosition) {
		if(motionPosition == ListView.INVALID_POSITION)return;
		int x = (int) ev.getX();
		int y = (int) ev.getY();
		int dx = Math.abs(x - mDownX);
		int dy = Math.abs(y - mDownY);
		switch (ev.getAction()) {
			case MotionEvent.ACTION_DOWN:
				if (mLastTouchPosition != motionPosition && System.currentTimeMillis() - first < doubleTapTimeout) {
					mHandler.removeCallbacks(clickR);
					onSingleTap(mLastTouchPosition);
				}
				mLastTouchPosition = motionPosition;
				mDownX = (int) ev.getX();
				mDownY = (int) ev.getY();
				isClick = true;
				mHandler.postDelayed(longPressR, longPressTimeout);
				break;
			case MotionEvent.ACTION_MOVE:
				if (dx >= slop || dy >= slop) {
					mHandler.removeCallbacks(longPressR);
					mHandler.removeCallbacks(clickR);
					isClick = false;
				}
				break;
			case MotionEvent.ACTION_CANCEL:
			case MotionEvent.ACTION_UP:
				mHandler.removeCallbacks(longPressR);
				if (isClick) {
					if (System.currentTimeMillis() - first < doubleTapTimeout) {
						mHandler.removeCallbacks(clickR);
						onDoubleTap();
					} else {
						if(OnDoubleClickListener==null)doubleTapTimeout = 0;
						mHandler.postDelayed(clickR, doubleTapTimeout);
						first = System.currentTimeMillis();
					}
				}
				break;
		}
	}
	private void onSingleTap(int position) {
		int selectNum = mSelecteds.size();
		switch (currentMode) {
			case mode0:
				radio(position);
				break;
			case mode1:
				multiselect(position);
				break;
			case mode2:
				continuity(position);
				break;
		}
		mObj.invalidateViews();
		if (selectNum != mSelecteds.size()) {
			if (OnSelectNumChangeListener != null)
				OnSelectNumChangeListener.selectChange(mSelecteds.size(), getCount());
		}
	}

	private void radio(int position) {
		mSelecteds.clear();
		mSelecteds.add(position);
		checkPostionKeep();
	}

	private void multiselect(int position) {
		if (!mSelecteds.remove(position))
			mSelecteds.add(position);
		if (mFirstSelect == -1)
			mFirstSelect = position;
		checkPostionKeep();
	}

	public void continuity(int position) {
		if (mFirstSelect == -1) {
			mFirstSelect = position;
			mSelecteds.add(position);
		} else {
			int start = Math.min(position, mFirstSelect);
			int end = Math.max(position, mFirstSelect);
			if (start != end) {
				mSelecteds.clear();
				for (int i = start; i <= end; i++) {
					mSelecteds.add(i);
				}
			} else if (start == end && mSelecteds.size() > 1) {
				mSelecteds.clear();
				mSelecteds.add(start);
			} else {
				mSelecteds.clear();
			}
		}
		checkPostionKeep();
	}

	private void onDoubleTap() {
		if (OnDoubleClickListener != null)
			OnDoubleClickListener.onClick(mLastTouchPosition);
	}

	public void setChoiceMode() {

	}

	public static enum Mode {
		RADIO(mode0), MULTISELECT(mode1), CONTINUITY(mode2), REVERSESELECT(mode3), SELECTALL(mode4), CLEAR(mode5);
		int value;

		private Mode(int value) {
			this.value = value;
		}
	}

	public void initSelectMode() {
		currentMode = mode0;
	}

	private String[] mode;
	private static final int mode0 = 0;
	private static final int mode1 = 1;
	private static final int mode2 = 2;
	private static final int mode3 = 3;
	private static final int mode4 = 4;
	private static final int mode5 = 5;
	private int currentMode = mode0;
	private Set<Integer> mSelecteds = new HashSet<Integer>();
	private OnDoubleClickListener OnDoubleClickListener;
	private int parmPosition;
	private OnSelectNumChangeListener OnSelectNumChangeListener;

	private void onLongPress() {
		AlertDialog dialog = DialogUtils.singleChoice(getContext(), mode, currentMode, new SingleChoiceListener() {
			@Override
			public void onClick(DialogInterface dialog, int selected, CharSequence choice) {
				currentMode = selected;
				if (selected == mode3) {
					currentMode = mode0;
					reverseSelect();
				} else if (selected == mode4) {
					currentMode = mode0;
					SelectAll();
				} else if (selected == mode5) {
					currentMode = mode0;
					init();
				}
				dialog.dismiss();
			}

		});
		dialog.show();
	}

	private void SelectAll() {
		int selectNum = mSelecteds.size();
		int end = getCount();
		for (int i = 0; i < end; i++) {
			mSelecteds.add(i);
		}
		mObj.invalidateViews();
		if (selectNum != mSelecteds.size()) {
			if (OnSelectNumChangeListener != null)
				OnSelectNumChangeListener.selectChange(mSelecteds.size(), getCount());
		}
	}

	private int getCount() {
		return (listCount == -1) ? mObj.getAdapter().getCount() : listCount;
	}

	private void checkPostionKeep() {
		if (mSelecteds.size() == 0) {
			mFirstSelect = -1;
		} else if (mSelecteds.size() == 1 || mFirstSelect == -1) {
			mFirstSelect = (Integer) mSelecteds.toArray()[0];
		}
	}

	private void reverseSelect() {
		int selectNum = mSelecteds.size();
		int start = 0;
		int end = getCount();
		for (int i = start; i < end; i++) {
			if (!mSelecteds.remove(i))
				mSelecteds.add(i);
		}
		checkPostionKeep();
		mObj.invalidateViews();
		if (selectNum != mSelecteds.size()) {
			if (OnSelectNumChangeListener != null)
				OnSelectNumChangeListener.selectChange(mSelecteds.size(), getCount());
		}
	}
	public boolean isChecked(int pos){
		return mSelecteds.contains(pos);
	}
	public void setOnDoubleClickListener(OnDoubleClickListener l) {
		this.OnDoubleClickListener = l;
	}


	public interface OnSelectNumChangeListener {
		void selectChange(int selectNum, int count);
	}

	public void setOnSelectChangeListener(OnSelectNumChangeListener l) {
		this.OnSelectNumChangeListener = l;
	}

	public interface OnDoubleClickListener {
		void onClick(int position);
	}

	public void init() {
		int size = mSelecteds.size();
		mSelecteds.clear();
		checkPostionKeep();
		if (OnSelectNumChangeListener != null&&size>0)
			OnSelectNumChangeListener.selectChange(0, getCount());
		if(size>0)
			mObj.invalidateViews();
	}

	public Collection<? extends Integer> getSelecteds() {
		return mSelecteds;
	}
}
public class SelectableListView extends ListView {
	private SelectHelper mOperationList;

	public SelectableListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public SelectableListView(Context context) {
		super(context);
		init(context, null);
	}

	public SelectableListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {
		mOperationList = new SelectHelper(context, attrs, this);
	}

	@SuppressLint("ClickableViewAccessibility")
	public boolean onTouchEvent(MotionEvent ev) {
		pos = pointToPosition((int) ev.getX(), (int) ev.getY());
		mOperationList.onTouchEvent(ev, pos);
		return super.onTouchEvent(ev);
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		throw new RuntimeException();
	}
	public void setAdapter(SelectableListViewAdapter adapter) {
		super.setAdapter(adapter);
	}

	public static abstract class SelectableListViewAdapter extends BaseAdapter{
		@Override
		public final View getView(int position, View convertView, ViewGroup parent) {
			SelectableListView listView = (SelectableListView) parent;
			return getView(position, convertView, parent,listView.isChildChecked(position));
		}
		public abstract View getView(int position, View convertView, ViewGroup parent,boolean isChecked);
	}

	private boolean isChildChecked(int pos) {
		return mOperationList.isChecked(pos);
	}

	private int pos = -1;

	public void setOnDoubleClickListener(final OnDoubleClickListener l) {
		mOperationList.setOnDoubleClickListener(new SelectHelper.OnDoubleClickListener() {
			@Override
			public void onClick(int position) {
				l.onClick(position);
			}
		});
	}

	public interface OnDoubleClickListener {
		void onClick(int position);
	}

	public interface OnSelectNumChangeListener {
		/**
		 *
		 * @param position
		 *            OnTouchPos
		 * @param selectNum
		 * @param count
		 */
		void selectChange(int position, int selectNum, int count);
	}

	public void setOnSelectChangeListener(final OnSelectNumChangeListener l) {
		mOperationList.setOnSelectChangeListener(new SelectHelper.OnSelectNumChangeListener() {
			@Override
			public void selectChange(int selectNum, int count) {
				l.selectChange(pos, selectNum, count);
			}
		});
	}

	public List<Integer> getSelecteds() {
		List<Integer> list = new ArrayList<Integer>();
		list.addAll(mOperationList.getSelecteds());
		return list;
	}

	public void clear() {
		mOperationList.init();
	}

	public void initSelectMode() {
		mOperationList.initSelectMode();
	}
}
public class SelectableExpandListView extends ExpandableListView {

	public final static int CHILD = 1;
	public final static int GROUP = 2;
	private Object mChildConnector;
	private Method getUnflattenedPosMethod;
	private Field positionField;
	private Field typeField;
	private Field childPosField;
	private Field groupPosField;
	private Method recycleMethod;
	private SelectHelper mOperationList;
	private int mCurrentGroupPosition = -1;

	public SelectableExpandListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	public SelectableExpandListView(Context context) {
		super(context, null);
	}

	public SelectableExpandListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {
		mOperationList = new SelectHelper(context, attrs, this);
	}


	@SuppressLint("ClickableViewAccessibility")
	public boolean onTouchEvent(MotionEvent ev) {
		int x = (int) ev.getX();
		int y = (int) ev.getY();
		int pos = pointToPosition(x, y);
		Object posMetadata = null;
		try {
			posMetadata = getUnflattenedPosMethod.invoke(mChildConnector, pos);
			Object postion = positionField.get(posMetadata);
			int type = typeField.getInt(postion);
			groupPos = groupPosField.getInt(postion);
			if (type == GROUP) {
				if (ev.getAction() == MotionEvent.ACTION_UP && groupPos != -1)
					checkGroupPosKeep(groupPos);
			} else if (type == CHILD) {
				childPos = childPosField.getInt(postion);
				if (ev.getAction() == MotionEvent.ACTION_UP)
					checkGroupPosKeep(groupPos);
				mOperationList.onTouchEvent(ev, childPos);
			}
		} catch (Exception e) {
		} finally {
			try {
				recycleMethod.invoke(posMetadata);
			} catch (Exception e) {
			}
		}
		return super.onTouchEvent(ev);
	}

	private void checkGroupPosKeep(int groupPos) {
		if (mCurrentGroupPosition != groupPos) {
			if (mCurrentGroupPosition != -1)
				mOperationList.init();
			mCurrentGroupPosition = groupPos;
			mOperationList.setListCount(getExpandableListAdapter()
					.getChildrenCount(groupPos));
		}
	}

	@Override
	public void setAdapter(ExpandableListAdapter adapter) {
		throw new RuntimeException("");
	}

	public void setAdapter(SelectableExpandableListAdapter adapter) {
		super.setAdapter(adapter);
		try {
			Field mConnectorField = SelectableExpandListView.class.getSuperclass().getDeclaredField("mConnector");
			mConnectorField.setAccessible(true);
			mChildConnector = mConnectorField.get(this);
			Class<?> clazz = Class.forName("android.widget.ExpandableListConnector");
			getUnflattenedPosMethod = clazz.getDeclaredMethod("getUnflattenedPos", int.class);
			getUnflattenedPosMethod.setAccessible(true);
			clazz = Class.forName("android.widget.ExpandableListConnector$PositionMetadata");
			recycleMethod = clazz.getDeclaredMethod("recycle");
			positionField = clazz.getDeclaredField("position");
			positionField.setAccessible(true);
			clazz = Class.forName("android.widget.ExpandableListPosition");
			typeField = clazz.getDeclaredField("type");
			typeField.setAccessible(true);
			childPosField = clazz.getDeclaredField("childPos");
			childPosField.setAccessible(true);
			groupPosField = clazz.getDeclaredField("groupPos");
			groupPosField.setAccessible(true);

		} catch (Exception e) {
		}
	}

	public static abstract class SelectableExpandableListAdapter extends BaseExpandableListAdapter {
		@Override
		public final View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
			SelectableExpandListView listView = (SelectableExpandListView) parent;
			return getChildView(groupPosition, childPosition, isLastChild, convertView, parent, listView.isChildChecked(groupPosition, childPosition));
		}

		public abstract View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent, boolean isChecked);
	}

	private boolean isChildChecked(int groupPosition, int childPosition) {
		return groupPosition == mCurrentGroupPosition && mOperationList.isChecked(childPosition);
	}

	public interface OnSelectNumChangeListener {
		/**
		 * @param childPos  OnTouchPos
		 * @param selectNum
		 * @param count
		 * @param groupPos
		 */
		void selectChange(int groupPos, int childPos, int selectNum, int count);
	}

	public void setOnSelectChangeListener(final OnSelectNumChangeListener l) {
		mOperationList.setOnSelectChangeListener(new SelectHelper.OnSelectNumChangeListener() {
			public void selectChange(int selectNum, int count) {
				l.selectChange(groupPos, childPos, selectNum, count);
			}
		});

	}

	public interface OnDoubleClickListener {
		void onClick(int group, int position);
	}

	private int childPos;
	private int groupPos;

	public void setOnDoubleClickListener(final OnDoubleClickListener l) {
		mOperationList.setOnDoubleClickListener(new SelectHelper.OnDoubleClickListener() {
			public void onClick(int position) {
				l.onClick(mCurrentGroupPosition, position);
			}
		});
	}

	@SuppressLint("UseSparseArrays")
	public Map<Integer, Collection<? extends Integer>> getSelecteds() {
		Collection<? extends Integer> selecteds = mOperationList.getSelecteds();
		Map<Integer, Collection<? extends Integer>> map = new HashMap<Integer, Collection<? extends Integer>>();
		map.put(mCurrentGroupPosition, selecteds);
		return map;
	}

	public void clear() {
		mOperationList.init();
	}

	public void initSelectMode() {
		mOperationList.initSelectMode();
	}
}

 

转载于:https://my.oschina.net/SSS555/blog/838555

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值