目标:实现类似QQ,微信的消息列表滑动删除

具体操作:

1. 主页面布局

首先在布局文件(本例是activity_main.xml)中引入ListView控件,并指定id(如下代码中黑体部分)。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"><ListViewandroid:id="@+id/list_view"android:layout_width="match_parent"android:layout_height="match_parent"/>
</RelativeLayout>

2. 定义滑动布局类

我们需有个工具类提供滑动的布局效果,即监听触摸动作,产生页面滑动效果。github上有很多强大的滑动类,博主最终引用了非常简易,容易操作的SwipeLayout.java。(如果你不关心滑动布局的实现机制,那么在工程中创建SwipeLayout.java类,拷贝附录1中的代码可。如果你想了解更多,可参考博客见具体实现过程:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0422/2771.html)

3. 定制ListView子项的布局

ListView确定的是整体样式,即列表排列,我们还可以定制列表中每行所放内容的样式。接下来我们的目标是像QQ信息列表那样,每行以图片开头,图片旁是联系人姓名。所以,在drawable目录下准备几张头像图片以及删除按钮的图标,然后在layout目录下新建activity_item.xml,代码如下所示:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent">

    <!--引用步骤2中添加的SwipeLayout.java布局类,包名为你项目中SwaipeLayout.java存放的路径--><com.example.whjth.swipelayout_demo.SwipeLayoutandroid:layout_width="match_parent"android:layout_height="50dp">        <LinearLayoutandroid:layout_width="match_parent"android:layout_height="50dp"android:background="#ffffff"><ImageViewandroid:id="@+id/image"android:layout_width="50dp"android:layout_height="50dp"android:padding="5dp"android:src="@drawable/p10"/>     <!--p10为存放在drawable目录下的头像图片名称--><TextViewandroid:id="@+id/name"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_gravity="center_horizontal"android:padding="5dp"android:layout_marginLeft="10dp"android:text= "xingming"/></LinearLayout><LinearLayoutandroid:layout_width="50dp"android:layout_height="50dp"><RelativeLayoutandroid:id="@+id/delete_button"android:clickable="true"android:layout_width="50dp"android:layout_height="50dp"android:background="#ff0000"><Viewandroid:layout_centerInParent="true"android:layout_width="28dp"android:layout_height="28dp"android:background="@drawable/trash"/>  <!--trash为删除图标--></RelativeLayout></LinearLayout> </com.example.whjth.swipelayout_demo.SwipeLayout>
</LinearLayout>

在上述代码中,第二个LinearLayout标签的宽度属性是“match_parent",这代表它与父布局(屏幕)宽度相同,从而遮蔽了第三个LineaLayout的内容,无法显现,只有通过滑动才可见。效果如下面左图所示;如果注释掉第二个LinearLayout内容,则可以看见第三个LinearLayout中的内容,如下面右图所示。

     

4. 创建展示内容的类对象

    布局文件都准备好了,下面就是往列表中写入内容了。我们发现列表中的每一项都具有同样的属性,即图片+名称。所以为了方便操作,我们把准备写入的内容当成一个类对象,为它定义图片和名称属性,实质上就是一个Java Bean。本例将其命名为Person.java,代码见下:

public class Person {private String name;private int ImageId;public Person(String name, int ImageId){this.name = name;this.ImageId = ImageId;}public String getName(){return name;}public int getImageId(){return ImageId;}
}

5. 定义传递数据至ListView的适配器

    让我们暂时停一下,理理思路,总结一下之前的工作:(1)我们在总布局中引入ListView控件(2)并为它定制了样式(3)载入了可以感知滑动的工具类(4)又将需要放入其中的内容整理成了类对象,这使我们可以通过数组的形式引用大量数据。

所以,我们剩下的工作是将数据传递到ListView中。不过,数组中的数据无法直接传递给ListView的,我们需要借助适配器完成。Android中提供了很多适配器的实现类,本例中使用的是ArrayAdapter。它可以通过泛型来指定要适配的数据类型(本例数据类型为步骤4中定义的Person),然后在构造函数中把要适配的数据传入, 然后在ArrayAdapter的构造函数中依次传入当前上下文、ListView子项布局的id,以及要适配的数据。本例将其命名为PersonAdapter.java,代码见下:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import java.util.List;public class PersonAdapter extends ArrayAdapter<Person>{private int resourceId;private Context context;
    /* 重写构造函数,即上文中划横线部分的实现 */public PersonAdapter(Context context, int textViewResourceId, List<Person> objects){super(context, textViewResourceId, objects);resourceId = textViewResourceId;this.context = context;}    /* 重写getView()方法,该方法在每个子项被滚动到屏幕内的时候会被调用 */public View getView(int position, View convertView, final ViewGroup parent){final Person person = getItem(position); //获取当前项的Person实例View view;ViewHolder viewHolder;  //下文中定义的内部类,用于保存image,name,delete等实例,而不是每次滑动加载时都通过findViewById的方法获得控件实例/* getView()方法中的converView参数表示之前加载的布局 */if(convertView == null){            /* 如果converView参数值为null,则使用LayoutInflater去加载布局 */            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);viewHolder = new ViewHolder();
            /* 调用View的findViewById()方法分别获得image和name实例 */
            viewHolder.image = (ImageView) view.findViewById(R.id.image);viewHolder.name = (TextView) view.findViewById(R.id.name);viewHolder.delete = view.findViewById(R.id.delete_button);view.setTag(viewHolder);}else{            /* 否则,直接对converView进行重用 */view = convertView;viewHolder = (ViewHolder) view.getTag();}

        /* 调用setImageResource()和setText()方法来设置显示的图片和文字 */viewHolder.image.setImageResource(person.getImageId());viewHolder.name.setText(person.getName());
        /* 以下黑体为事件监听响应部分,即点击删除图标和头像会分别显示提醒信息 */
        viewHolder.delete = view.findViewById(R.id.delete_button);viewHolder.delete.setOnClickListener(new View.OnClickListener(){public void onClick(View v){Toast.makeText(getContext(), "you clicked delete button", Toast.LENGTH_SHORT).show();}});viewHolder.image.setOnClickListener(new View.OnClickListener(){public void onClick(View v){Toast.makeText(getContext(), "you clicked image", Toast.LENGTH_SHORT).show();}});return view; //返回布局}class ViewHolder{ImageView image;TextView name;View delete;}
}

数据适配完成,下面只用在主程序中调用ListView的setAdapter()方法,将构建好的适配器对象传递进去,这样ListView和数据之间的关联就完成了。

6. 编写主程序

在主程序中初始化列表条目,并通过适配器将其值传入ListView。参考代码MainActivity.java见下:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {private List<Person> PersonList = new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initPerson();PersonAdapter adapter = new PersonAdapter(MainActivity.this, R.layout.activity_item, PersonList);ListView listView = (ListView) findViewById(R.id.list_view);listView.setAdapter(adapter);}private void initPerson(){for(int i=0; i<2; i++) {Person person = new Person("Alex", R.drawable.p1);PersonList.add(person);person = new Person("Brandon", R.drawable.p2);PersonList.add(person);person = new Person("Charles", R.drawable.p3);PersonList.add(person);person = new Person("Davie", R.drawable.p4);PersonList.add(person);person = new Person("Eric", R.drawable.p5);PersonList.add(person);person = new Person("Fanny", R.drawable.p6);PersonList.add(person);person = new Person("Grace", R.drawable.p7);PersonList.add(person);person = new Person("Helen", R.drawable.p8);PersonList.add(person);person = new Person("Isabelle", R.drawable.p9);PersonList.add(person);person = new Person("Jenny", R.drawable.p10);PersonList.add(person);}}
}

效果图:

附录1:SwipeLayout.java

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
/*** Created by Bruce on 11/24/14.*/
public class SwipeLayout extends LinearLayout {private ViewDragHelper viewDragHelper;private View contentView;private View actionView;private int dragDistance;private final double AUTO_OPEN_SPEED_LIMIT = 800.0;private int draggedX;public SwipeLayout(Context context) {this(context, null);}public SwipeLayout(Context context, AttributeSet attrs) {this(context, attrs, -1);}public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);viewDragHelper = ViewDragHelper.create(this, new DragHelperCallback());}@Overrideprotected void onFinishInflate() {contentView = getChildAt(0);actionView = getChildAt(1);actionView.setVisibility(GONE);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);dragDistance = actionView.getMeasuredWidth();}private class DragHelperCallback extends ViewDragHelper.Callback {@Overridepublic boolean tryCaptureView(View view, int i) {return view == contentView || view == actionView;}@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {draggedX = left;if (changedView == contentView) {actionView.offsetLeftAndRight(dx);} else {contentView.offsetLeftAndRight(dx);}if (actionView.getVisibility() == View.GONE) {actionView.setVisibility(View.VISIBLE);}invalidate();}@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {if (child == contentView) {final int leftBound = getPaddingLeft();final int minLeftBound = -leftBound - dragDistance;final int newLeft = Math.min(Math.max(minLeftBound, left), 0);return newLeft;} else {final int minLeftBound = getPaddingLeft() + contentView.getMeasuredWidth() - dragDistance;final int maxLeftBound = getPaddingLeft() + contentView.getMeasuredWidth() + getPaddingRight();final int newLeft = Math.min(Math.max(left, minLeftBound), maxLeftBound);return newLeft;}}@Overridepublic int getViewHorizontalDragRange(View child) {return dragDistance;}@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {super.onViewReleased(releasedChild, xvel, yvel);boolean settleToOpen = false;if (xvel > AUTO_OPEN_SPEED_LIMIT) {settleToOpen = false;} else if (xvel < -AUTO_OPEN_SPEED_LIMIT) {settleToOpen = true;} else if (draggedX <= -dragDistance / 2) {settleToOpen = true;} else if (draggedX > -dragDistance / 2) {settleToOpen = false;}final int settleDestX = settleToOpen ? -dragDistance : 0;viewDragHelper.smoothSlideViewTo(contentView, settleDestX, 0);ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);}}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if(viewDragHelper.shouldInterceptTouchEvent(ev)) {return true;}return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {viewDragHelper.processTouchEvent(event);return true;}@Overridepublic void computeScroll() {super.computeScroll();if(viewDragHelper.continueSettling(true)) {ViewCompat.postInvalidateOnAnimation(this);}}
}

项目完整源代码下载:https://github.com/Vera97/ListView-SwipeLayout-Demo

转载于:https://www.cnblogs.com/ticktack/p/7028306.html

Android ListView滑动删除及响应事件详解相关推荐

  1. android中用名字删除,安卓手机文件名详解~~~让你了解每个文件的作用,放心删除无用文件...

    三方应用类 1..mobo:Moboplayer的缓存文件. 2..QQ:QQ的缓存文件,需要定期清除. 3..quickoffice:quickoffice的缓存文件. 4..switchpro:s ...

  2. android 拖动 点击事件,Android事件详解——拖放事件DragEvent

    1.Android拖放框架的作用? 利用Android的拖放框架,可以让用户用拖放手势把一个View中的数据移到当前layout内的另一个View中去. 2.拖放框架的内容? 1)拖放事件类 2)拖放 ...

  3. ListView滑动删除效果实现

    通过继承ListView然后结合PopupWindow实现 首先是布局文件: delete_btn.xml:这里只需要一个Button <?xml version="1.0" ...

  4. android触摸滑动监听,Android 滑动监听的实例详解

    Android 滑动监听的实例详解 摘要: ScollBy,ScollTo是对内容的移动,view.ScollyBy是对view的内容的移动 view,ScollTo是对内容的移动(移动到指定位置), ...

  5. android listview remove 动画,给Android ListView添加删除item动画

    给Android ListView添加删除item动画 给listview删除一个item的时候加上一个折叠动画,感觉效果会好一点. 步骤是当删除一个view,先用动画把view的高度改变,看上去就是 ...

  6. android 截图 listview,Android屏幕及view的截图实例详解

    Android屏幕及view的截图实例详解 屏幕可见区域的截图 整个屏幕截图的话可以用View view = getWindow().getDecorView(); public static Bit ...

  7. html5触屏滑动事件,HTML5的touch事件详解

    原标题:HTML5的touch事件详解 HTML5中新添加了很多事件,比较常看到的是touch事件,下面来详解下html5中的触摸touch事件. touchstart:触摸开始的时候触发touchm ...

  8. android底部滑动出现虚拟按键,Android适配底部虚拟按键的方法详解

    Android适配底部虚拟按键的方法详解 发布时间:2020-10-09 05:26:12 来源:脚本之家 阅读:171 作者:yuanzhihui123 最近项目进行适配的时候发现部分(如华为手机) ...

  9. Android 8.0学习(32)---Android 8.0源码目录结构详解

    Android 8.0源码目录结构详解 android的移植按如下流程:     (1)android linux 内核的普通驱动移植,让内核可以在目标平台上运行起来.     (2)正确挂载文件系统 ...

最新文章

  1. Mysql中对table的操作问题
  2. Sklearn 损失函数如何应用到_15 分钟带你入门 sklearn 与机器学习(分类算法篇)...
  3. 第六周---事后分析
  4. xtrabackup安装使用
  5. 霍金首次公开24岁时博士论文 把剑桥的服务器搞瘫痪了……
  6. 【原创】全面剖析飞凌2440,6410开发板选型指南
  7. python函数递归 字符串反转
  8. IT测试时准确数据的技巧(IT总结之三去除旧数据)
  9. Linux配置Selenium+Chrome+Java实现自动化测试
  10. 12个新鲜出炉的Web开发框架
  11. PHP htmlspecialchars() 函数
  12. 10个Python实战编程项目,有趣又好玩
  13. Linux read系统调用
  14. 一卡通管理系统数据库服务器连接失败,智能一卡通管理系统数据库服务器连接失败...
  15. pentaho mysql_pentaho5.0.1,mysql5 配置,安装
  16. 售前是做什么的?需要具备什么能力?
  17. uniapp:轮播里如何加入视频
  18. 如何利用SQL注入进行爆库
  19. 九、redis的删除机制
  20. CAD梦想画图中的的“绘图工具——绘线命令”

热门文章

  1. echarts 多组图例重叠问题
  2. 三只大老虎和三只小老虎过河
  3. java 本周一_java 获取本周一的日期
  4. R语言中作图字体的设置
  5. C++找文件夹中,最长的名字有多长
  6. 随笔感悟:Mysql悲观锁和乐观锁
  7. vivado各版本的区别
  8. 以Python角度学习Javascript(一)
  9. java和php做网站区别_做网站java与php的区别是什么?
  10. Hive案例 学生成绩表综合案例