Android 自定义ListView实现左划删除
2017-04-05 17:31
225 查看
项目中遇到一个要求 在listview 列表中左划item 显示删除按钮(仿QQ获取微信左划删除)
步骤1.自定义listview 本人用到了万能刷新 所以多了一步实现Pullable接口 如果没有需求 可以删除
/**
* listview 左划删除
* */
public class SwipeListView extends ListView implements Pullable{
private Boolean mIsHorizontal;
private View mPreItemView;
private View mCurrentItemView;
private float mFirstX;
private float mFirstY;
private int mRightViewWidth;
private final int mDuration = 100;
private final int mDurationStep = 10;
private boolean mIsShown;
public SwipeListView(Context context) {
this(context, null);
}
public SwipeListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray mTypedArray = context.obtainStyledAttributes(attrs,R.styleable.swipelistviewstyle);
//获取自定义属性和默认值
mRightViewWidth = (int) mTypedArray.getDimension(R.styleable.swipelistviewstyle_right_width, 200);
mTypedArray.recycle();
}
/**
* return true, deliver to listView. return false, deliver to child. if
* move, return true
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
float lastX = ev.getX();
float lastY = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mIsHorizontal = null;
mFirstX = lastX;
mFirstY = lastY;
int motionPosition = pointToPosition((int) mFirstX, (int) mFirstY);
if (motionPosition >= 0) {
View currentItemView = getChildAt(motionPosition
- getFirstVisiblePosition());
mPreItemView = mCurrentItemView;
mCurrentItemView = currentItemView;
}
break;
case MotionEvent.ACTION_MOVE:
float dx = lastX - mFirstX;
float dy = lastY - mFirstY;
if (Math.abs(dx) >= 5 && Math.abs(dy) >= 5) {
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mIsShown&& (mPreItemView != mCurrentItemView || isHitCurItemLeft(lastX))) {
/**
* 情况一:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候点击任意一个item, 那么那个右边布局显示的item隐藏其右边布局
*/
hiddenRight(mPreItemView);
}
break;
}
return super.onInterceptTouchEvent(ev);
}
private boolean isHitCurItemLeft(float x) {
return x < getWidth() - mRightViewWidth;
}
/**
* @param dx
* @param dy
* @return judge if can judge scroll direction
*/
private boolean judgeScrollDirection(float dx, float dy) {
boolean canJudge = true;
if (Math.abs(dx) > 30 && Math.abs(dx) > 2 * Math.abs(dy)) {
mIsHorizontal = true;
} else if (Math.abs(dy) > 30 && Math.abs(dy) > 2 * Math.abs(dx)) {
mIsHorizontal = false;
} else {
canJudge = false;
}
return canJudge;
}
/**
* return false, can't move any direction. return true, cant't move
* vertical, can move horizontal. return super.onTouchEvent(ev), can move
* both.
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
float lastX = ev.getX();
float lastY = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
float dx = lastX - mFirstX;
float dy = lastY - mFirstY;
if (mIsHorizontal == null) {
if (!judgeScrollDirection(dx, dy)) {
break;
}
}
if (mIsHorizontal) {
if (mIsShown && mPreItemView != mCurrentItemView) {
/**
* 情况二:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候左右滑动另外一个item,那个右边布局显示的item隐藏其右边布局
* <p>
* 向左滑动只触发该情况,向右滑动还会触发情况五
*/
hiddenRight(mPreItemView);
}
if (mIsShown && mPreItemView == mCurrentItemView) {
dx = dx - mRightViewWidth;
}
// can't move beyond boundary
if (dx < 0 && dx > -mRightViewWidth) {
mCurrentItemView.scrollTo((int) (-dx), 0);
}
return true;
} else {
if (mIsShown) {
/**
* 情况三:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候上下滚动ListView,那么那个右边布局显示的item隐藏其右边布局
*/
hiddenRight(mPreItemView);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
clearPressedState();
if (mIsShown) {
/**
* 情况四:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候左右滑动当前一个item,那个右边布局显示的item隐藏其右边布局
*/
hiddenRight(mPreItemView);
}
if (mIsHorizontal != null && mIsHorizontal) {
if (mFirstX - lastX > mRightViewWidth / 2) {
showRight(mCurrentItemView);
} else {
/**
* 情况五:
* <p>
* 向右滑动一个item,且滑动的距离超过了右边View的宽度的一半,隐藏之。
*/
hiddenRight(mCurrentItemView);
}
return true;
}
break;
}
return super.onTouchEvent(ev);
}
private void clearPressedState() {
if(mCurrentItemView!=null){
mCurrentItemView.setPressed(false);
}
setPressed(false);
refreshDrawableState();
}
private void showRight(View view) {
Message msg = new MoveHandler().obtainMessage();
msg.obj = view;
msg.arg1 = view.getScrollX();
msg.arg2 = mRightViewWidth;
msg.sendToTarget();
mIsShown = true;
}
private void hiddenRight(View view) {
if (mCurrentItemView == null) {
return;
}
Message msg = new MoveHandler().obtainMessage();//
msg.obj = view;
msg.arg1 = view.getScrollX();
msg.arg2 = 0;
msg.sendToTarget();
mIsShown = false;
}
/**
* show or hide right layout animation
*/
@SuppressLint("HandlerLeak")
class MoveHandler extends Handler {
int stepX = 0;
int fromX;
int toX;
View view;
private boolean mIsInAnimation = false;
private void animatioOver() {
mIsInAnimation = false;
stepX = 0;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (stepX == 0) {
if (mIsInAnimation) {
return;
}
mIsInAnimation = true;
view = (View) msg.obj;
fromX = msg.arg1;
toX = msg.arg2;
stepX = (int) ((toX - fromX) * mDurationStep * 1.0 / mDuration);
if (stepX < 0 && stepX > -1) {
stepX = -1;
} else if (stepX > 0 && stepX < 1) {
stepX = 1;
}
if (Math.abs(toX - fromX) < 10) {
view.scrollTo(toX, 0);
animatioOver();
return;
}
}
fromX += stepX;
boolean isLastStep = (stepX > 0 && fromX > toX)
|| (stepX < 0 && fromX < toX);
if (isLastStep) {
fromX = toX;
}
view.scrollTo(fromX, 0);
invalidate();
if (!isLastStep) {
this.sendEmptyMessageDelayed(0, mDurationStep);
} else {
animatioOver();
}
}
}
public int getRightViewWidth() {
return mRightViewWidth;
}
public void setRightViewWidth(int mRightViewWidth) {
this.mRightViewWidth = mRightViewWidth;
}
@Override
public boolean canPullDown() {//下拉刷新
if(getCount()==0){
return false;
}else if(getFirstVisiblePosition()==0&&getChildAt(0).getTop()>=0){//滑到ListView的顶部了
return true;
}else{
return false;
}
}
@Override
public boolean canPullUp() {//上拉更多
if(getCount()==0){
return false;
}else if(getLastVisiblePosition()==(getCount()-1)){//滑到底部了
if(getChildAt(getLastVisiblePosition()-getFirstVisiblePosition())!=null&&getChildAt(getLastVisiblePosition()-getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()){
return true;
}else{
return false;
}
}else{
return false;
}
}
}
2.adapter 中
private onRightItemClickListener mListener=null;
public void setOnRightItemClickListener(onRightItemClickListener listener){
mListener=listener;
}
vh.item_left=(LinearLayout) arg1.findViewById(R.id.positionmanagementlistview_leftlayout);
vh.item_right=(LinearLayout) arg1.findViewById(R.id.positionmanagementlistview_rightlayout);
//动态获取left 和right的宽度
LinearLayout.LayoutParams lp1=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
vh.item_left.setLayoutParams(lp1);
LinearLayout.LayoutParams lp2=new LayoutParams(mRightWidth, LayoutParams.MATCH_PARENT);
vh.item_right.setLayoutParams(lp2);
vh.item_right.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(mListener!=null) {
mListener.onRightItemClick(arg0, pp);
}
}
});
3.activity页面中
//左划删除
adapter.setOnRightItemClickListener(new onRightItemClickListener() {
@Override
public void onRightItemClick(View v, int position) {
String name=list.get(position).getTitle();
toast.showToast("删除"+name);
}
});
步骤1.自定义listview 本人用到了万能刷新 所以多了一步实现Pullable接口 如果没有需求 可以删除
/**
* listview 左划删除
* */
public class SwipeListView extends ListView implements Pullable{
private Boolean mIsHorizontal;
private View mPreItemView;
private View mCurrentItemView;
private float mFirstX;
private float mFirstY;
private int mRightViewWidth;
private final int mDuration = 100;
private final int mDurationStep = 10;
private boolean mIsShown;
public SwipeListView(Context context) {
this(context, null);
}
public SwipeListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray mTypedArray = context.obtainStyledAttributes(attrs,R.styleable.swipelistviewstyle);
//获取自定义属性和默认值
mRightViewWidth = (int) mTypedArray.getDimension(R.styleable.swipelistviewstyle_right_width, 200);
mTypedArray.recycle();
}
/**
* return true, deliver to listView. return false, deliver to child. if
* move, return true
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
float lastX = ev.getX();
float lastY = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mIsHorizontal = null;
mFirstX = lastX;
mFirstY = lastY;
int motionPosition = pointToPosition((int) mFirstX, (int) mFirstY);
if (motionPosition >= 0) {
View currentItemView = getChildAt(motionPosition
- getFirstVisiblePosition());
mPreItemView = mCurrentItemView;
mCurrentItemView = currentItemView;
}
break;
case MotionEvent.ACTION_MOVE:
float dx = lastX - mFirstX;
float dy = lastY - mFirstY;
if (Math.abs(dx) >= 5 && Math.abs(dy) >= 5) {
return true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mIsShown&& (mPreItemView != mCurrentItemView || isHitCurItemLeft(lastX))) {
/**
* 情况一:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候点击任意一个item, 那么那个右边布局显示的item隐藏其右边布局
*/
hiddenRight(mPreItemView);
}
break;
}
return super.onInterceptTouchEvent(ev);
}
private boolean isHitCurItemLeft(float x) {
return x < getWidth() - mRightViewWidth;
}
/**
* @param dx
* @param dy
* @return judge if can judge scroll direction
*/
private boolean judgeScrollDirection(float dx, float dy) {
boolean canJudge = true;
if (Math.abs(dx) > 30 && Math.abs(dx) > 2 * Math.abs(dy)) {
mIsHorizontal = true;
} else if (Math.abs(dy) > 30 && Math.abs(dy) > 2 * Math.abs(dx)) {
mIsHorizontal = false;
} else {
canJudge = false;
}
return canJudge;
}
/**
* return false, can't move any direction. return true, cant't move
* vertical, can move horizontal. return super.onTouchEvent(ev), can move
* both.
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
float lastX = ev.getX();
float lastY = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
float dx = lastX - mFirstX;
float dy = lastY - mFirstY;
if (mIsHorizontal == null) {
if (!judgeScrollDirection(dx, dy)) {
break;
}
}
if (mIsHorizontal) {
if (mIsShown && mPreItemView != mCurrentItemView) {
/**
* 情况二:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候左右滑动另外一个item,那个右边布局显示的item隐藏其右边布局
* <p>
* 向左滑动只触发该情况,向右滑动还会触发情况五
*/
hiddenRight(mPreItemView);
}
if (mIsShown && mPreItemView == mCurrentItemView) {
dx = dx - mRightViewWidth;
}
// can't move beyond boundary
if (dx < 0 && dx > -mRightViewWidth) {
mCurrentItemView.scrollTo((int) (-dx), 0);
}
return true;
} else {
if (mIsShown) {
/**
* 情况三:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候上下滚动ListView,那么那个右边布局显示的item隐藏其右边布局
*/
hiddenRight(mPreItemView);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
clearPressedState();
if (mIsShown) {
/**
* 情况四:
* <p>
* 一个Item的右边布局已经显示,
* <p>
* 这时候左右滑动当前一个item,那个右边布局显示的item隐藏其右边布局
*/
hiddenRight(mPreItemView);
}
if (mIsHorizontal != null && mIsHorizontal) {
if (mFirstX - lastX > mRightViewWidth / 2) {
showRight(mCurrentItemView);
} else {
/**
* 情况五:
* <p>
* 向右滑动一个item,且滑动的距离超过了右边View的宽度的一半,隐藏之。
*/
hiddenRight(mCurrentItemView);
}
return true;
}
break;
}
return super.onTouchEvent(ev);
}
private void clearPressedState() {
if(mCurrentItemView!=null){
mCurrentItemView.setPressed(false);
}
setPressed(false);
refreshDrawableState();
}
private void showRight(View view) {
Message msg = new MoveHandler().obtainMessage();
msg.obj = view;
msg.arg1 = view.getScrollX();
msg.arg2 = mRightViewWidth;
msg.sendToTarget();
mIsShown = true;
}
private void hiddenRight(View view) {
if (mCurrentItemView == null) {
return;
}
Message msg = new MoveHandler().obtainMessage();//
msg.obj = view;
msg.arg1 = view.getScrollX();
msg.arg2 = 0;
msg.sendToTarget();
mIsShown = false;
}
/**
* show or hide right layout animation
*/
@SuppressLint("HandlerLeak")
class MoveHandler extends Handler {
int stepX = 0;
int fromX;
int toX;
View view;
private boolean mIsInAnimation = false;
private void animatioOver() {
mIsInAnimation = false;
stepX = 0;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (stepX == 0) {
if (mIsInAnimation) {
return;
}
mIsInAnimation = true;
view = (View) msg.obj;
fromX = msg.arg1;
toX = msg.arg2;
stepX = (int) ((toX - fromX) * mDurationStep * 1.0 / mDuration);
if (stepX < 0 && stepX > -1) {
stepX = -1;
} else if (stepX > 0 && stepX < 1) {
stepX = 1;
}
if (Math.abs(toX - fromX) < 10) {
view.scrollTo(toX, 0);
animatioOver();
return;
}
}
fromX += stepX;
boolean isLastStep = (stepX > 0 && fromX > toX)
|| (stepX < 0 && fromX < toX);
if (isLastStep) {
fromX = toX;
}
view.scrollTo(fromX, 0);
invalidate();
if (!isLastStep) {
this.sendEmptyMessageDelayed(0, mDurationStep);
} else {
animatioOver();
}
}
}
public int getRightViewWidth() {
return mRightViewWidth;
}
public void setRightViewWidth(int mRightViewWidth) {
this.mRightViewWidth = mRightViewWidth;
}
@Override
public boolean canPullDown() {//下拉刷新
if(getCount()==0){
return false;
}else if(getFirstVisiblePosition()==0&&getChildAt(0).getTop()>=0){//滑到ListView的顶部了
return true;
}else{
return false;
}
}
@Override
public boolean canPullUp() {//上拉更多
if(getCount()==0){
return false;
}else if(getLastVisiblePosition()==(getCount()-1)){//滑到底部了
if(getChildAt(getLastVisiblePosition()-getFirstVisiblePosition())!=null&&getChildAt(getLastVisiblePosition()-getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()){
return true;
}else{
return false;
}
}else{
return false;
}
}
}
2.adapter 中
private onRightItemClickListener mListener=null;
public void setOnRightItemClickListener(onRightItemClickListener listener){
mListener=listener;
}
vh.item_left=(LinearLayout) arg1.findViewById(R.id.positionmanagementlistview_leftlayout);
vh.item_right=(LinearLayout) arg1.findViewById(R.id.positionmanagementlistview_rightlayout);
//动态获取left 和right的宽度
LinearLayout.LayoutParams lp1=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
vh.item_left.setLayoutParams(lp1);
LinearLayout.LayoutParams lp2=new LayoutParams(mRightWidth, LayoutParams.MATCH_PARENT);
vh.item_right.setLayoutParams(lp2);
vh.item_right.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(mListener!=null) {
mListener.onRightItemClick(arg0, pp);
}
}
});
3.activity页面中
//左划删除
adapter.setOnRightItemClickListener(new onRightItemClickListener() {
@Override
public void onRightItemClick(View v, int position) {
String name=list.get(position).getTitle();
toast.showToast("删除"+name);
}
});
相关文章推荐
- Android系列之自定义ListView实现左右滑删除
- Android系列之自定义ListView实现左右滑删除
- Android自定义Dialog,实现长按ListView删除当中item数据
- Android自定义ListView实现仿微信侧滑删除
- 【Android游戏开发二十三】自定义ListView【通用】适配器并实现监听控件!
- 【Android游戏开发二十三】自定义ListView【通用】适配器并实现监听控件!
- android 开源项目(二)可以左右拖动删除、调换位置的的listview的 item的实现(drag-sort-listview)
- 实现自定义view(2):仿Android QQ多屏幕显示ListView的效果
- Android中自定义Adapter实现ListView动态刷新进度条
- 【Android游戏开发二十三】自定义ListView【通用】适配器并实现监听控件!
- android 自定义ScrollView实现反弹效果(以及解决和ListView之间的冲突)
- (转)【Android游戏开发二十三】自定义ListView【通用】适配器并实现监听控件!
- android自定义listview实现圆角
- Android中自定义Adapter实现ListView动态刷新进度条
- Android的Master/Detail风格界面中实现自定义ListView的单选
- android listView 自定义布局结合CheckedTextView实现多选
- Android开发:setContentView切换界面,自定义带CheckBox的ListView显示SQlite条目-----实现
- 【Android游戏开发二十三】自定义ListView【通用】适配器并实现监听控件!
- android自定义listview实现圆角
- Android---自定义带CheckBox的ListView实现