自己实现一个右滑删除的ListView, SwipeMenuListView
来源:互联网 发布:中华姓氏家谱编辑软件 编辑:程序博客网 时间:2024/05/17 23:52
参考了以下源码:https://github.com/baoyongzhang/SwipeMenuListView
实现的效果(顺便推荐一个视频转gif的网址:http://www.gif5.net/)
实现的效果包括:
1.左滑item出现menu view,
- 左滑距离过短时自动关掉menu view,
- 左滑距离超过一定值时自动打开menu view,
2.menu view打开的时候,
- 右滑能够关闭menu view;
- 右滑超过一定的值时松开自动关闭menu view
- 右滑距离过短时松开,自动使menu view仍然是打开状态
- 点击其他item关闭menu view
- 点击menu view是打开的item,但是点击区域不在menu view上的时候关闭menu view
- 点击menu view中的按钮,实现相应的操作(具体事件处理见代码)
首先抛出几个问题:
1.如何根据我们的手势判定要左滑的position
2.滑动到什么程度让左滑的Menu显示出来
3.怎么处理item左滑与ListView的滑动的冲突
4.menu怎么添加
5.只能有一个是Open的状态,如果Item1是Open,这时候点击或者滑动Item2,应该使Item1关闭(拦截触摸事件,稍候详细添加)
首先,定义一个CustomSlideDeleteItemView,这个View的layout要重写,确定menu的摆放位置,具体见代码
package com.example.myapp.view;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.FrameLayout;import android.widget.LinearLayout;import android.widget.TextView;import com.example.myapp.R;import com.example.myapp.util.Methods;import java.util.ArrayList;import java.util.List;/** * Created by zyr * DATE: 16-3-19 * Time: 下午3:54 * Email: yanru.zhang@renren-inc.com */public class CustomSlideDeleteItemView extends FrameLayout{ private Context mContext; private List<View> menuViews = new ArrayList<>(); private View contentView; public LinearLayout getMenuViewContainer() { return menuViewContainer; } private LinearLayout menuViewContainer; private int contentViewId; private int contentViewWidth,contentViewHeight,menuWidth,menuHeight; private int menuState = MENU_STATE_CLOSE; public final static int MENU_STATE_CLOSE = 0; public final static int MENU_STATE_OPEN = 1; public final static int MENU_STATE_HALF_OPEN = 2; public void setOnMenuClickListener(OnMenuClickListener onMenuClickListener) { this.onMenuClickListener = onMenuClickListener; } private OnMenuClickListener onMenuClickListener; public interface OnMenuClickListener{ void onMenuClick(int i,int counts); } public CustomSlideDeleteItemView(Context context) { this(context, null); } public CustomSlideDeleteItemView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomSlideDeleteItemView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; menuWidth = Methods.computePixelsWithDensity(mContext,100);// Log.d("zyr","menuWidth:" + menuWidth); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomSlideDeleteItemView); for(int i=0;i<typedArray.length();i++){ int attr = typedArray.getIndex(i); switch (attr){ case R.styleable.CustomSlideDeleteItemView_contentViewId: contentViewId = typedArray.getResourceId(R.styleable.CustomSlideDeleteItemView_contentViewId,0); break; } } if(contentViewId!=0){ contentView = findViewById(contentViewId); } menuViewContainer = new LinearLayout(mContext); menuViewContainer.setOrientation(LinearLayout.HORIZONTAL); ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); addView(menuViewContainer, layoutParams); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if(contentView!=null){ contentView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight()); } layoutMenu(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if(w!=oldw || h!=oldh){ contentViewHeight = menuHeight = h; contentViewWidth = w;// Log.d("zyr","contentViewWidth:" + contentViewWidth); } } public void addMenu(String s,int color){ TextView textView = new TextView(mContext); textView.setText(s); textView.setBackgroundColor(color); textView.setTextColor(getResources().getColor(R.color.white)); textView.setGravity(Gravity.CENTER); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(menuWidth, ViewGroup.LayoutParams.MATCH_PARENT); menuViews.add(textView); menuViewContainer.addView(textView, layoutParams); invalidate(); for(int i=0;i<menuViews.size();i++){ final int position = i; View view = menuViews.get(i); view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(onMenuClickListener!=null){ onMenuClickListener.onMenuClick(position,menuViews.size()); scrollClose(); } } }); } } public void clearAllMenu(){ menuViews.clear(); menuViewContainer.removeAllViews(); invalidate(); } private void layoutMenu() { menuViewContainer.layout(contentViewWidth, 0, contentViewWidth + menuWidth * menuViews.size(), contentViewHeight); } public void scroll(int deltaX,int lastDeltaX) { if(deltaX < 0){// Log.d("zyr","deltaX:" + deltaX);// Log.e("zyr","menuWidth * menuViews.size():" + menuWidth * menuViews.size()); if(Math.abs(deltaX) > menuWidth * menuViews.size() ){ scrollTo(menuWidth * menuViews.size(), 0); menuState = MENU_STATE_OPEN; }else{ scrollBy(-lastDeltaX, 0); menuState = MENU_STATE_HALF_OPEN; } }else{ if( !isClosed() ){// Log.d("zyr","deltaX:" + deltaX);// Log.e("zyr", "menuWidth * menuViews.size():" + menuWidth * menuViews.size()); if(Math.abs(deltaX) > menuWidth * menuViews.size()){ scrollTo(0,0); menuState = MENU_STATE_CLOSE; }else{ scrollBy(-lastDeltaX, 0); menuState = MENU_STATE_HALF_OPEN; } } } } public void autoScroll(int deltaX){ if(deltaX < 0){ if(Math.abs(deltaX) < menuWidth){ scrollTo(0, 0); menuState = MENU_STATE_CLOSE; }else{ scrollTo(menuWidth * menuViews.size(), 0); menuState = MENU_STATE_OPEN; } }else{ if( !isClosed() ){ if(Math.abs(deltaX) < menuWidth){ scrollTo(menuWidth * menuViews.size(), 0); menuState = MENU_STATE_OPEN; }else{ scrollTo(0,0); menuState = MENU_STATE_CLOSE; } } } } public void scrollClose(){ scrollTo(0,0); menuState = MENU_STATE_CLOSE; } public boolean isClosed(){ if(menuState == MENU_STATE_CLOSE){ return true; }else{ return false; } }}
在attr文件中定义
<declare-styleable name="CustomSlideDeleteItemView"> <attr name="contentViewId" format="integer"/> </declare-styleable>
然后定义我们的CustomSlideDeleteListView
package com.example.myapp.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Color;import android.graphics.drawable.ColorDrawable;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.ListView;import com.example.myapp.R;import com.example.myapp.util.Methods;/** * Created by zyr * DATE: 16-3-18 * Time: 下午5:42 * Email: yanru.zhang@renren-inc.com * 参照:https://github.com/baoyongzhang/SwipeMenuListView * 还有一些没有解决的问题, * 1.触摸拦截 */public class CustomSlideDeleteListView extends ListView { private Context mContext; private CustomSlideDeleteItemView mCurrentView,mLastTouchItemView; private int currentItemId,lastItemId,touchItemId; private int downX,downY,moveX,moveY,deltaX,deltaY,upX,upY,lastX,lastDeltaX; public final static int MIN_SCROLL_DIS = 100; private int touchState=TOUCH_STATE_NONE; public final static int TOUCH_STATE_X = 1; public final static int TOUCH_STATE_Y = 2; public final static int TOUCH_STATE_NONE = 0; private int direction = DIRECTION_NONE; public final static int DIRECTION_LEFT = 1;//左滑 public final static int DIRECTION_RIGHT = 2;//右滑 public final static int DIRECTION_TOP = 3;//左滑 public final static int DIRECTION_BOTTOM = 4;//右滑 public final static int DIRECTION_NONE = 0;// public CustomSlideDeleteListView(Context context) { this(context, null); } public CustomSlideDeleteListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomSlideDeleteListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; setSelector(new ColorDrawable(Color.TRANSPARENT)); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomSlideDeleteListView); for(int i=0;i<typedArray.length();i++){ int attr = typedArray.getIndex(i); switch (attr){ case R.styleable.CustomSlideDeleteListView_rightViewId: break; } } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: lastX = downX = (int) ev.getX(); downY = (int) ev.getY(); touchItemId = pointToPosition(downX,downY); touchState = TOUCH_STATE_NONE; break; case MotionEvent.ACTION_MOVE: moveX = (int) ev.getX(); moveY = (int) ev.getY(); deltaX = moveX - downX; deltaY = moveY - downY; lastDeltaX = moveX - lastX; lastX = moveX; if(Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > MIN_SCROLL_DIS){ touchState = TOUCH_STATE_X; if(deltaX > 0){ direction = DIRECTION_RIGHT; }else{ direction = DIRECTION_LEFT; } }else if(Math.abs(deltaX) <= Math.abs(deltaY) && Math.abs(deltaY) > MIN_SCROLL_DIS){ touchState = TOUCH_STATE_Y; if(deltaY > 0){ direction = DIRECTION_BOTTOM; }else{ direction = DIRECTION_TOP; } }else { touchState = TOUCH_STATE_NONE; direction = DIRECTION_NONE; }// Log.e("zyr","touchState:" + touchState);// Log.e("zyr","direction"+ direction); break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: //按下的位置不是上次按下的位置 //上次的iew不是空,而且是打开的,拦截 if(touchItemId != lastItemId && mLastTouchItemView!=null && !mLastTouchItemView.isClosed()){ return true; } break; case MotionEvent.ACTION_MOVE: //if 向距离大于纵向距离,拦截 if(touchState == TOUCH_STATE_X ){ return true; } break; case MotionEvent.ACTION_UP: //只是点击了一下 //有处于Open状态的menu //没有点击在menu上面,拦截 if(touchState==TOUCH_STATE_NONE && mLastTouchItemView!=null && !mLastTouchItemView.isClosed() && !Methods.inRangeOfView(mLastTouchItemView.getMenuViewContainer(),ev)){ return true; } break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: if(touchItemId != lastItemId && mLastTouchItemView!=null && !mLastTouchItemView.isClosed()){ mLastTouchItemView.scrollClose(); return true; } break; case MotionEvent.ACTION_MOVE: if(touchState == TOUCH_STATE_X ){ lastItemId = currentItemId; currentItemId = pointToPosition(downX,downY); mLastTouchItemView = mCurrentView; mCurrentView = (CustomSlideDeleteItemView)getChildAt(currentItemId - getFirstVisiblePosition()); mCurrentView.scroll(deltaX,lastDeltaX); return true; } break; case MotionEvent.ACTION_UP: upX = (int)ev.getX(); upY = (int)ev.getY(); if(touchState == TOUCH_STATE_X && mCurrentView!=null){ mCurrentView.autoScroll(upX - downX); return true; } if(touchState==TOUCH_STATE_NONE && mLastTouchItemView!=null && !mLastTouchItemView.isClosed() && !Methods.inRangeOfView(mLastTouchItemView.getMenuViewContainer(),ev)){ mLastTouchItemView.scrollClose(); return true; } break; } return super.onTouchEvent(ev); }}
最后需要定义我们的Adapter
package com.example.myapp.adapter;import android.content.Context;import android.graphics.Color;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.Filter;import android.widget.Filterable;import android.widget.TextView;import android.widget.Toast;import com.example.myapp.R;import com.example.myapp.view.CustomSlideDeleteItemView;import java.util.ArrayList;import java.util.List;/** * Created by zyr * DATE: 15-11-26 * Time: 下午2:52 * Email: yanru.zhang@renren-inc.com */public class CustomSlideDeleteListViewAdapter extends BaseAdapter implements Filterable{ public List<String> arrayList = new ArrayList<String>(); private Context context; private MyFilter mFilter; public CustomSlideDeleteListViewAdapter(Context context){ this.context = context; } public CustomSlideDeleteListViewAdapter(Context context, List<String> arrayList){ this.context = context; this.arrayList = new ArrayList<String>(arrayList); } public void setData(List<String> array){ if(array ==null){ return; } arrayList = new ArrayList<String>(array); notifyDataSetChanged(); } @Override public int getCount() { return arrayList.size(); } @Override public Object getItem(int position) { return arrayList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if(convertView ==null){ convertView = LayoutInflater.from(context).inflate(R.layout.list_view_item,null); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); }else{ viewHolder = (ViewHolder)convertView.getTag(); } viewHolder.itemView.clearAllMenu(); viewHolder.itemView.addMenu("Delete", Color.RED); viewHolder.itemView.addMenu("Open", Color.BLUE); viewHolder.itemView.scrollBack(); viewHolder.textView.setText(arrayList.get(position)); viewHolder.itemView.setOnMenuClickListener(new CustomSlideDeleteItemView.OnMenuClickListener() { @Override public void onMenuClick(int i, int counts) { switch (i){ case 0: arrayList.remove(position); notifyDataSetChanged(); break; case 1: break; } } }); return convertView; } @Override public Filter getFilter() { if (mFilter == null) { mFilter = new MyFilter(); } return mFilter; } class MyFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if (arrayList == null) { arrayList = new ArrayList<String>(); } results.values = arrayList; results.count = arrayList.size(); return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } class ViewHolder{ CustomSlideDeleteItemView itemView; TextView textView; public ViewHolder(View view){ itemView = (CustomSlideDeleteItemView)view; textView = (TextView)view.findViewById(R.id.list_view_text); } }}
adapter引用的xml文件
<?xml version="1.0" encoding="utf-8"?><com.example.myapp.view.CustomSlideDeleteItemView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@drawable/common_listview_bg" app:contentViewId="@+id/list_view_text"> <TextView android:id="@+id/list_view_text" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:textColor="@color/primary" android:textStyle="bold" android:paddingLeft="20dp" /></com.example.myapp.view.CustomSlideDeleteItemView>
在Activity中引用
customSlideDeleteListView = (CustomSlideDeleteListView) findViewById(R.id.custom_slid_delete_list_view); for(int i=0;i<100;i++){ stringList.add("zyr" + i); } customSlideDeleteListViewAdapter = new CustomSlideDeleteListViewAdapter(this,stringList); customSlideDeleteListView.setAdapter(customSlideDeleteListViewAdapter);
1 0
- 自己实现一个右滑删除的ListView, SwipeMenuListView
- Android 实现ListView item的左滑(右滑)监听事件 swipemenulistview
- ListView侧滑删除(SwipeMenuListView)
- 侧滑删除ListView:SwipeMenuListView
- 用SwipeMenuListView库实现listview左滑删除功能
- 实现SwipeMenuListView特定item的右滑menu无效
- ListView侧滑删除的实现,利用SwipemenuListView开源框架
- 记一个SwipeMenuListView侧滑删除错乱的Bug
- 仿QQ侧滑删除Item:Swipemenulistview的简单实现
- 仿QQ侧滑删除Item:Swipemenulistview的简单实现
- SwipeMenuListView实现点击和侧滑删除
- 侧滑删除 SwipeMenuListView的使用
- SwipeMenuListview侧滑删除
- Android listview 右滑删除
- SwipeMenuListView,一个简单的左滑操作
- SwipeMenuListView 左滑实现:置顶 标为未读 删除
- SwipeMenuListView实现类似于QQ侧滑删除效果
- 自己实现一个下拉刷新的ListView
- 谈谈对Spring IOC的理解
- 添加、显示表情图片
- 泛型 简谈
- maven部署web项目到weblogic中
- 触发Full GC执行的情况 JVM对象分配规则
- 自己实现一个右滑删除的ListView, SwipeMenuListView
- [PHP代码] 用php的fsocket模拟get提交 模拟post提交表单
- matlab下创建带变量的文件夹
- BZOJ 1194: [HNOI2006]潘多拉的盒子
- 【字符串处理算法】获取最长公共子串的算法设计及C代码实现
- <php>学习小记-20160322
- 数字签名与数字证书
- Jena读取Ontology本体到Mysql数据库
- 安卓触摸事件探究