Android 仿QQListView侧滑删除
来源:互联网 发布:java 微信发送消息 编辑:程序博客网 时间:2024/04/25 14:41
先上效果图
分析下整个效果如何实现
1.每一个item的界面如何去控制,做出类似动画一样的效果
2.对onTouchEvent事件的处理
想下,是不是只要每一个item处理好,做出这种效果之后,那么剩下的问题就相对简单多了
那好首先我们来看下,如何来实现item的侧滑效果
我们的每一个itme的布局都是由两部分组成一个是主view一个是侧滑view,所以这两个view我们需要在构造方法中传入,并且,我们不需要在xml文件中添加,所以只需要实现一参的构造方法就行了
package wkk.demo15;import android.support.v4.widget.ScrollerCompat;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.LinearLayout;/** * Created by wkk on 2016/6/12. */public class SlidingMenuViewGroup extends LinearLayout { //实现滚动操作 private ScrollerCompat scrollerCompat; //按下的x点坐标 private int xDown; //主布局以及菜单布局 private View contentView; private View menuView; //菜单是否打开 private boolean isOpen; //1构造方法,这里传入两个view,一个是主布局,一个是侧面的布局 public SlidingMenuViewGroup(View contentView, View menuView) { super(contentView.getContext()); this.contentView = contentView; this.menuView = menuView; init(); } private void init() { setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); scrollerCompat = ScrollerCompat.create(getContext()); contentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); menuView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); addView(contentView); addView(menuView); }}
以上代码并不难理解,不过是定义一些所必要的参数,并且初始化一些数据,这里就不多做赘述
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //设置menuView的测量模式 //此处宽必须设置为UNSPECIFIED 否则将不会绘制 menuView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) , MeasureSpec.makeMeasureSpec(menuView.getMeasuredHeight(), MeasureSpec.EXACTLY)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); //指定contentview和menuView的位置 contentView.layout(0, 0, getMeasuredWidth(), getMeasuredHeight()); menuView.layout(getMeasuredWidth(), 0, getMeasuredWidth() + menuView.getMeasuredWidth(), getMeasuredHeight()); }
MainActivity代码:
package wkk.demo15;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.TypedValue;import android.view.Gravity;import android.view.ViewGroup;import android.widget.TextView;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setView(); } private void setView() { TextView textView1 = new TextView(this); textView1.setText("content"); textView1.setGravity(Gravity.CENTER); textView1.setBackgroundColor(0xffff123f); textView1.setHeight(dp2px(70)); TextView textView2 = new TextView(this); textView2.setGravity(Gravity.CENTER); textView2.setWidth(dp2px(70)); textView2.setHeight(dp2px(70)); textView2.setText("menu"); textView2.setBackgroundColor(0xbbbbbbbb); SlidingMenuViewGroup sildingMenuViewGroup = new SlidingMenuViewGroup(textView1, textView2); addContentView(sildingMenuViewGroup, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(70))); } //尺寸转化 private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); }}
此时效果如上图,如果用鼠标点击,并没有任何作用,当然,这些都是准备工作,接下来进行关键的onTouchEvent的事件处理
@Override public boolean onTouchEvent(MotionEvent event) { onEvent(event); return true; } public void onEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //记录坐标 xDown = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: //滑动的距离 int distance = (int) (xDown - event.getX()); if (isOpen) { //此处需要弄清楚getWidth和getMeasuredWidth的区别 //getWidth的到的宽度是显示在屏幕中的部分 //getMeasuredWidth,如果有屏幕之外的部分即,未显示的部分,那么getMeasuredWidth的到宽度是 //实际宽度即显示在屏幕中的宽度和屏幕之外的宽度,如果在屏幕中已近完全显示,那么得到的部分即和getWidth相同 distance += menuView.getWidth(); } sliding(distance); break; case MotionEvent.ACTION_UP: break; } } //滑动 private void sliding(int distance) { //控制最大最小距离 if (distance < 0) { distance = 0; } if (distance > menuView.getMeasuredWidth()) { distance = menuView.getMeasuredWidth(); } //重新设置位置 contentView.layout(-distance, 0, getWidth() - distance, getHeight()); menuView.layout(getWidth() - distance, 0, getWidth() + menuView.getMeasuredWidth() - distance, getHeight()); }
效果如图:
可以看到,我们所要的效果已经有了雏形,但是,滑动并不流畅,当然,或许你已经注意到我们在上边定义的ScrollerCompat,并没有用到,那么接下来,对up事件进行处理的时候就会用到ScrollerCompat
case MotionEvent.ACTION_UP: //判断滑动距离是否大于menuview的一半 // 如果大于就打开,否则就关闭菜单 if ((xDown - event.getX()) > (menuView.getMeasuredWidth() / 2)) { openMenu(); } else { closeMenu(); } break;
public void closeMenu() { isOpen = false; //参数:x轴起始位置,y轴起始位置,x轴偏移量,y轴偏移量,时间 //偏移量为正时,向右移动,偏移量为负时,向右移动 scrollerCompat.startScroll(contentView.getLeft(), 0, -contentView.getLeft(), 0, 300); //通知重绘 postInvalidate(); } public void openMenu() { isOpen = true; //再调用这个方法后view就会调用computeScroll方法,所以要对其进行重写 scrollerCompat.startScroll(contentView.getLeft(), 0, -(menuView.getWidth() + contentView.getLeft()), 0, 300); postInvalidate(); } @Override public void computeScroll() { super.computeScroll(); //判断是否完成滑动 if (scrollerCompat.computeScrollOffset()) { //scrollerCompat.getCurrX() 获取当前x轴的滑动位置 sliding(Math.abs(scrollerCompat.getCurrX())); postInvalidate(); } }
效果如下图
可以看到效果已经是我们想要的效果了,而且滑动也很流畅了,这里在添加下对外部提供的方法:
//对外部提供方法 public boolean isOpen() { return isOpen; } public View getMenuView(){ return menuView; }
好,至此,item已经基本完成了,可是,这当然不是最终效果,对onTouchEvent事件,我们当然不可以全部拦截,还有如果你设置了contentview的点击事件,你会发现,滑动就失效了,所以,我门还要自定义listview,如果你对listview的onTouchEvent事件不去处理的话,直接使用原生,就会发现很多奇怪的现象,并不是我们想要的效果,如果有兴趣,可以去试试看呐
首先将SlidingMenuViewGroup的onTouchEvent事件还原
@Override public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); }
重写ListView,定义相关变量
package wkk.demo15;import android.content.Context;import android.util.AttributeSet;import android.util.TypedValue;import android.widget.ListView;/** * Created by wkk on 2016/6/12. */public class SlidingMenuListView extends ListView { //滑动最小值 private int MIN_X; private int MIN_Y; //按下点坐标 private int xDown; private int yDown; //当前的子view private SlidingMenuViewGroup sildingMenu; //手指所在item位置 private int position; private int oldposition; //移动状态 private int touchState; private int TOUCK_STATE_NULL = 0; private int TOUCH_STATE_X = 1; private int TOUCH_STATE_Y = 2; //移动距离 private int dx; private int dy; private boolean is; public SlidingMenuListView(Context context, AttributeSet attrs) { super(context, attrs); MIN_X = dp2px(3); MIN_Y = dp2px(5); } //尺寸转化 private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); }}
最关键的onTouchEvent事件处理:
@Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //首先记录坐标 xDown = (int) ev.getX(); yDown = (int) ev.getY(); oldposition = position; //状态设置为null touchState = TOUCK_STATE_NULL; is = false; position = pointToPosition(xDown, yDown); //如果两次按下时的位置相同,并且菜单是打开的 if (oldposition == position && sildingMenu != null && sildingMenu.isOpen()) { touchState = TOUCH_STATE_X; sildingMenu.onEvent(ev); return true; } //如果两次按下的位置不同,并且菜单是打开的 if (sildingMenu != null && sildingMenu.isOpen()) { //直接关闭菜单 sildingMenu.closeMenu(); sildingMenu = null; //这种情况下,不去响应up事件 is = true; return true; } //得到view View view = getChildAt(position - getFirstVisiblePosition()); //判断view是否是SildingMenuViewGroup的对象 if (view instanceof SlidingMenuViewGroup) { sildingMenu = (SlidingMenuViewGroup) view; } if (sildingMenu != null) { sildingMenu.onEvent(ev); } break; case MotionEvent.ACTION_MOVE: //取得xy轴的偏移量 dx = (int) (xDown - ev.getX()); dy = (int) Math.abs(ev.getY() - yDown); if (touchState == TOUCK_STATE_NULL) { //判断 设置状态 优先判断Y if (dy > MIN_Y) { touchState = TOUCH_STATE_Y; } else if (dx > MIN_X) { touchState = TOUCH_STATE_X; } } else if (touchState == TOUCH_STATE_X) { //将事件传递给sildingMenu if (sildingMenu != null) { sildingMenu.onEvent(ev); } //取消,不处理 ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); return true; } break; case MotionEvent.ACTION_UP: if (touchState == TOUCH_STATE_X) { if (sildingMenu != null) { sildingMenu.onEvent(ev); //如果菜单是关的 重置 if (!sildingMenu.isOpen()) { position = -1; sildingMenu = null; } } ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); return true; } if (touchState == TOUCK_STATE_NULL) { if (is) { ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); return true; } } break; } return super.onTouchEvent(ev); }
至此,我们的ListView已经编写完成了,但是这样就行了吗?No,我们还有去对适配器进行修改,并且响应删除菜单的点击事件
MyBaseAdapter:
http://blog.csdn.net/w18756901575/article/details/51028177
Adapter:
package wkk.demo15;import android.content.Context;import android.util.TypedValue;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.RelativeLayout;import android.widget.TextView;/** * Created by wkk on 2016/6/12. */public class DemoAdapter extends MyBaseAdapter<String> { private MenuClickListener listener; public DemoAdapter(Context context) { super(context); } @Override public View getView(final int position, View convertView, ViewGroup parent) { SlidingMenuViewGroup viewGroup = null; ViewHold viewHold = null; if (convertView == null) { viewHold = new ViewHold(); View contentview = inflater.inflate(R.layout.item, null); TextView textView = new TextView(context); textView.setWidth(getDp(80)); textView.setHeight(getDp(80)); textView.setBackgroundColor(0xbbbbbbbb); textView.setGravity(Gravity.CENTER); textView.setText("删除"); textView.setTag(0); TextView textView1 = new TextView(context); textView1.setWidth(getDp(80)); textView1.setHeight(getDp(80)); textView1.setBackgroundColor(0xbbff123f); textView1.setGravity(Gravity.CENTER); textView1.setText("测试"); textView1.setTag(1); LinearLayout menu = new LinearLayout(context); menu.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT , ViewGroup.LayoutParams.MATCH_PARENT)); menu.addView(textView); menu.addView(textView1); viewHold.text = (TextView) contentview.findViewById(R.id.text); viewGroup = new SlidingMenuViewGroup(contentview, menu); viewGroup.setTag(viewHold); } else { viewGroup = (SlidingMenuViewGroup) convertView; viewHold = (ViewHold) viewGroup.getTag(); } viewHold.text.setText(getItem(position)); final ViewGroup menu = (ViewGroup) viewGroup.getMenuView(); final SlidingMenuViewGroup finalViewGroup = viewGroup; int count = menu.getChildCount(); for (int i = 0; i < count; i++) { View v = menu.getChildAt(i); v.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //将点击事件传递出去 if (listener != null) { int tag = (int) v.getTag(); listener.onMenuClickListener(v, position, finalViewGroup, tag); finalViewGroup.closeMenu(); } } }); } return viewGroup; } private class ViewHold { TextView text; } //提供外部监听 public void setListener(MenuClickListener listener) { this.listener = listener; } public interface MenuClickListener { void onMenuClickListener(View menu, int position, SlidingMenuViewGroup viewGroup, int tag); } private int getDp(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics()); }}
MainActivity:
package wkk.demo15;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.TypedValue;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.TextView;import android.widget.Toast;import java.util.List;public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { private SlidingMenuListView listView; private DemoAdapter adapter; private List<String> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (SlidingMenuListView) findViewById(R.id.listview); adapter = new DemoAdapter(this); list = adapter.getList(); for (int i = 0; i < 20; i++) { list.add("这是一条测试数据: " + String.valueOf(i)); } listView.setAdapter(adapter); listView.setOnItemClickListener(this); adapter.setListener(new DemoAdapter.MenuClickListener() { @Override public void onMenuClickListener(View menu, int position, SlidingMenuViewGroup viewGroup, int tag) { TextView textView = (TextView) menu; Toast.makeText(MainActivity.this, "点击了" + textView.getText(), Toast.LENGTH_SHORT).show(); if (tag == 0) { list.remove(position); adapter.notifyDataSetChanged(); } } }); } private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } private void setView() { TextView textView1 = new TextView(this); textView1.setText("content"); textView1.setGravity(Gravity.CENTER); textView1.setBackgroundColor(0xffff123f); textView1.setHeight(dp2px(70)); TextView textView2 = new TextView(this); textView2.setGravity(Gravity.CENTER); textView2.setWidth(dp2px(70)); textView2.setHeight(dp2px(70)); textView2.setText("menu"); textView2.setBackgroundColor(0xbbbbbbbb); SlidingMenuViewGroup sildingMenuViewGroup = new SlidingMenuViewGroup(textView1, textView2); addContentView(sildingMenuViewGroup, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(70))); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(this, "点击了" + String.valueOf(position), Toast.LENGTH_SHORT).show(); }}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout 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" android:orientation="vertical" tools:context="wkk.demo14.MainActivity"> <wkk.demo15.SlidingMenuListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent"> </wkk.demo15.SlidingMenuListView></LinearLayout>
item.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="80dp" android:gravity="center"> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="这是一条测试数据" /></LinearLayout>
至此,整个代码就编写完成了,效果图已经在一开始就贴了出来,这里就不贴了,当然,有兴趣的可以对整个Demo进行进一步的封装
Demo下载地址:
http://download.csdn.net/detail/w18756901575/9546912
- Android 仿QQlistview侧滑删除
- Android 仿QQListView侧滑删除
- 高仿QQlistview滑动删除+下拉刷新
- 仿QQlistView滑动删除---使用SwipeMenuListView实现
- QQListview左滑删除,经典案例,高仿QQ左滑,动画效果,自定义!!
- Android仿QQ侧滑删除实现
- android 仿qq的侧滑删除功能
- Android仿QQ侧滑删除(ViewDragHelper)
- android 侧滑删除库,高仿IOS,QQ
- 仿QQ侧滑删除
- 仿qq侧滑删除
- Android侧滑删除菜单,高仿QQ、IOS侧滑删除
- listview 侧滑删除 仿qq
- HorizontalScrollView仿QQ侧滑删除
- 仿qq列表侧滑删除
- 仿qq侧滑删除Item
- 仿QQ侧滑删除的ListView
- 仿QQ侧滑删除ListView
- linux 文件删除而空间没有释放的解决办法
- Program4_D
- java基础语法练习--输入年月日确定星期几
- localtime_r的实现
- ARM开发板移植lsusb命令
- Android 仿QQListView侧滑删除
- 大数运算——阶乘-40!
- 大整数减法计算思路与算法实现
- js得到url的各个部分
- Android 轻松实现仿淘宝地区选择
- Linux中文显示乱码?如何设置centos显示中文
- 用virtualBox安装centos设置网络和通信
- 如何在 Ubuntu 14.04 上通过 apt-get 安装 Apache Tomcat 7
- Android入门--android.graphics.Color 颜色设置