自定义SwipeLayout控件实现ListView条目侧滑出现删除按钮,点击实现删除ListView条目
来源:互联网 发布:mac什么视频播放器好 编辑:程序博客网 时间:2024/05/18 19:23
今天,我们来实现类似于QQ最近联系人的聊天记录向右滑动出现删除按钮的功能。效果图如下:
布局文件如下:
这里这需要自定义一个SwipeLayout实现滑动出现删除按钮的效果,SwipeLayout.java代码如下:
package com.example.myoperation;import android.content.Context;import android.graphics.Rect;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.FrameLayout;/** * 侧拉删除控件 */public class SwipeLayout extends FrameLayout { private Status status = Status.Close; private OnSwipeLayoutListener swipeLayoutListener; public Status getStatus() { return status; } public void setStatus(Status status) { this.status = status; } public OnSwipeLayoutListener getSwipeLayoutListener() { return swipeLayoutListener; } public void setSwipeLayoutListener(OnSwipeLayoutListener swipeLayoutListener) { this.swipeLayoutListener = swipeLayoutListener; } /** * 三种状态,关闭开启和正在拖拽 */ public static enum Status{ Close, Open, Draging } public static interface OnSwipeLayoutListener { void onClose(SwipeLayout mSwipeLayout); void onOpen(SwipeLayout mSwipeLayout); void onDraging(SwipeLayout mSwipeLayout); // 要去关闭 void onStartClose(SwipeLayout mSwipeLayout); // 要去开启 void onStartOpen(SwipeLayout mSwipeLayout); } /** * 第一步实现父类方法,初始化ViewDragHelper */ public SwipeLayout(Context context) { this(context, null); } public SwipeLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mDragHelper = ViewDragHelper.create(this, 1.0f, mCallback); } /** * 第三步重写触摸事件方法 */ ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() { /** * 根据返回结果决定当前child是否可以被拖拽 */ @Override public boolean tryCaptureView(View view, int id) { return true;//表示子View都可以被拖拽 } /** * 根据建议值修正将要移动到的(横向)位置 * @param child:当前拖拽的view * @param left:建议值 * return: 真正值 */ public int clampViewPositionHorizontal(View child, int left, int dx) { if(child == mFrontView){ if(left > 0){ return 0; }else if(left < -mRange){ return -mRange; } }else if (child == mBackView) { if(left > mWidth){ return mWidth; }else if (left < mWidth - mRange) { return mWidth - mRange; } } return left; } /** * 当View位置改变的时候。处理要做的事(更新状态,伴随动画,重绘界面) * @param changedView:改变位置的View * @param left:新的左边值 * @param dx:水平方向变化量 */ public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { // 传递事件,是两个布局同时移动 if(changedView == mFrontView){ mBackView.offsetLeftAndRight(dx); }else if (changedView == mBackView) { mFrontView.offsetLeftAndRight(dx); } dispatchSwipeEvent(); // 兼容老版本 invalidate(); } /** * 当View被释放的时候,处理的事情(执行动画) * @param releasedChild:被释放的子View * @param xvel:释放时水平方向的速度 * @param yvel:释放时竖直方向的速度 */ public void onViewReleased(View releasedChild, float xvel, float yvel) { if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) { //当水平方向无速度并且向左滑动的距离大于范围的一半则打开 open(); }else if (xvel < 0) { //当有水平方向向左的速度则打开 open(); }else { //其余情况关闭 close(); } } }; /** * 第二步将触摸事件传递给ViewDragHelper,计算子View宽高和移动范围 */ private ViewDragHelper mDragHelper; private View mBackView; private View mFrontView; private int mHeight; private int mWidth; private int mRange; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mDragHelper.shouldInterceptTouchEvent(ev); } protected void dispatchSwipeEvent() { if(swipeLayoutListener != null){ swipeLayoutListener.onDraging(this); } // 记录上一次的状态 Status preStatus = status; // 更新当前状态 status = updateStatus(); if (preStatus != status && swipeLayoutListener != null) { if (status == Status.Close) { swipeLayoutListener.onClose(this); } else if (status == Status.Open) { swipeLayoutListener.onOpen(this); } else if (status == Status.Draging) { if(preStatus == Status.Close){ swipeLayoutListener.onStartOpen(this); }else if (preStatus == Status.Open) { swipeLayoutListener.onStartClose(this); } } } } /** * 更新状态 */ private Status updateStatus() { int left = mFrontView.getLeft(); if(left == 0){ return Status.Close; }else if (left == -mRange) { return Status.Open; } return Status.Draging; } /** * 关闭条目 */ public void close() { close(true); } public void close(boolean isSmooth){ int finalLeft = 0; if(isSmooth){ //开始动画 if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){ ViewCompat.postInvalidateOnAnimation(this); } }else { layoutContent(false); } } public void open() { open(true); } public void open(boolean isSmooth){ int finalLeft = -mRange; if(isSmooth){ //开始动画 if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){ ViewCompat.postInvalidateOnAnimation(this); } }else { layoutContent(true); } } @Override public void computeScroll() { super.computeScroll(); //持续平滑动画 (高频率调用) if(mDragHelper.continueSettling(true)){ //如果返回true, 动画还需要继续执行 ViewCompat.postInvalidateOnAnimation(this); } } @Override public boolean onTouchEvent(MotionEvent event) { try { mDragHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } return true; } /** * 获取前后两个布局 */ @Override protected void onFinishInflate() { super.onFinishInflate(); // 当xml被填充完毕时调用 mBackView = getChildAt(0); mFrontView = getChildAt(1); } /** * 计算前后两个布局的宽高和移动的范围 */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mHeight = mFrontView.getMeasuredHeight(); mWidth = mFrontView.getMeasuredWidth(); mRange = mBackView.getMeasuredWidth(); } /** * 对前后两个布局进行摆放 */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // 摆放位置 layoutContent(false); } private void layoutContent(boolean isOpen) { // 摆放前View Rect frontRect = computeFrontViewRect(isOpen); mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom); // 摆放后View Rect backRect = computeBackViewViaFront(frontRect); mBackView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom); // 调整顺序, 把mFrontView前置 bringChildToFront(mFrontView); } /** * 计算前布局摆放的位置 */ private Rect computeFrontViewRect(boolean isOpen) { int left = 0; if(isOpen){ left = -mRange; } return new Rect(left, 0, left + mWidth, 0 + mHeight); } /** * 根据前布局计算后布局的位置 */ private Rect computeBackViewViaFront(Rect frontRect) { int left = frontRect.right; return new Rect(left, 0, left + mRange, 0 + mHeight); }}activity_main.xml布局文件代码如下:
<RelativeLayout 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" tools:context=".MainActivity" > <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/lv" > </ListView></RelativeLayout>listview的条目item_list布局文件如下,这里注意要使用自己定义的SwipeLayout控件作为根布局:
<?xml version="1.0" encoding="utf-8"?><com.example.myoperation.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/sl" android:layout_width="match_parent" android:layout_height="60dp" android:minHeight="60dp" android:background="#44000000" > <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/tv_call" android:layout_width="60dp" android:layout_height="match_parent" android:background="#666666" android:gravity="center" android:text="Call" android:textColor="#fff" /> <TextView android:id="@+id/tv_del" android:layout_width="60dp" android:layout_height="match_parent" android:background="#ff0000" android:gravity="center" android:text="Delete" android:textColor="#ffffff" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#44ffffff" android:gravity="center_vertical" android:orientation="horizontal" > <ImageView android:id="@+id/iv_image" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="15dp" android:src="@drawable/head_1" /> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="15dp" android:text="Name" /> </LinearLayout></com.example.myoperation.SwipeLayout>MainActivity.java布局文件如下:
package com.example.myoperation;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;import com.example.myoperation.SwipeLayout.OnSwipeLayoutListener;import java.util.ArrayList;public class MainActivity extends Activity { MyAdapter myAdapter; private ArrayList<SwipeLayout> opendItems = new ArrayList<>(); private ArrayList<String> NAMES = new ArrayList<>(); private ListView mList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mList = (ListView) findViewById(R.id.lv); initData(); myAdapter = new MyAdapter(); mList.setAdapter(myAdapter); } private void initData() { for (int i = 0; i < 20; i++){ NAMES.add("name"+i); } } public class MyAdapter extends BaseAdapter { @Override public int getCount() { return NAMES.size(); } @Override public String getItem(int position) { return NAMES.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null){ convertView = View.inflate(MainActivity.this, R.layout.item_list, null); holder = new ViewHolder(); holder.tv_name = (TextView)convertView.findViewById(R.id.tv_name); holder.tv_del = (TextView)convertView.findViewById(R.id.tv_del); convertView.setTag(holder); }else { holder = (ViewHolder)convertView.getTag(); } holder.tv_name.setText(getItem(position)); holder.tv_del.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { NAMES.remove(position); myAdapter.notifyDataSetChanged(); } }); /** * 设置listview滑动监听,当listview滑动时关闭已经开启的的Item */ mList.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { for (SwipeLayout layout : opendItems) { layout.close(); } opendItems.clear(); } }); /** * 设置SwipeLayout滑动监听,当新的Item开启时,关闭之前已经开启的Item */ SwipeLayout sl = (SwipeLayout)convertView; sl.setSwipeLayoutListener(new OnSwipeLayoutListener() { @Override public void onStartOpen(SwipeLayout mSwipeLayout) { for (SwipeLayout layout : opendItems) { layout.close(); } opendItems.clear(); } @Override public void onStartClose(SwipeLayout mSwipeLayout) { } @Override public void onOpen(SwipeLayout mSwipeLayout) { opendItems.add(mSwipeLayout); } @Override public void onDraging(SwipeLayout mSwipeLayout) { } @Override public void onClose(SwipeLayout mSwipeLayout) { opendItems.remove(mSwipeLayout); } }); return convertView; } } static class ViewHolder { TextView tv_name; TextView tv_del; }}将上述布局文件和java代码布局好,编译运行就可以实现listview向右滑动点击删除按钮达到删除条目的效果了。代码中的一些注意点我都注释了,如果有不明白的地方可以留言哦,我尽量帮大家解决。
0 0
- 自定义SwipeLayout控件实现ListView条目侧滑出现删除按钮,点击实现删除ListView条目
- ListView的条目侧滑显示删除按钮
- 删除listview条目
- Android中listview条目中按钮点击事件的实现
- 随便做着玩-实现删除选择ListView的条目
- 实现listview条目点击显示和隐藏
- ListView批量删除Item条目
- 自定义listVIew 实现条目文字渐变效果
- 自定义SwipeLayout--仿QQ侧滑条目
- ListView视图动态增加与删除控件条目,内容
- ListView 条目显示点击
- 点击listview条目跳转
- Android控件listView条目不能点击问题
- Android中ListView条目带有左滑显示删除按钮的总结
- 一个简单的方法实现ListView条目点击下方出现阴影
- ListView条目的多条删除
- ListView中的条目长按点击事件的实现
- 如何判断listview同一条目被多次点击 listview每个条目中有一个button 点击button可以删除条目中的数据
- Oracle数据库--实用操作(1)
- 关于Android的ActionBar不能显示左上角的图标解决方案
- static的使用
- android RelativeLayout属性和使用, 实现上面view叠加在下面view之上的效果
- csdn如何转载别人的文章
- 自定义SwipeLayout控件实现ListView条目侧滑出现删除按钮,点击实现删除ListView条目
- Error:No suitable device found: no device found for connection "System eth0"
- system generator与FPGA入门,第一个案例
- Linux centOS c语言 多线程编程学习笔记
- KNN算法
- 2017京东实习生笔试题(二)
- hdu5294(最大流+最短路)Tricks Device
- 学习记录--javascript多态
- codeforces 593E