本来准备在ListView的每个Item的布局上设置一个隐藏的Button,当滑动的时候显示。但是因为每次只要存在一个Button,发现每个Item上的Button相互间不好控制。所以决定继承ListView然后结合PopupWindow。
首先是布局文件:
delete_btn.xml:这里只需要一个Button
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" ><Buttonandroid:id="@+id/id_item_btn" android:layout_width="60dp" android:singleLine="true" android:layout_height="wrap_content" android:text="删除" android:background="@drawable/d_delete_btn" android:textColor="#ffffff" android:paddingLeft="15dp" android:paddingRight="15dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="15dp" /> </LinearLayout>
主布局文件:activity_main.xml,ListView的每个Item的样式直接使用了系统的android.R.layout.simple_list_item_1
<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" ><com.example.listviewitemslidedeletebtnshow.QQListView android:id="@+id/id_listview" android:layout_width="fill_parent" android:layout_height="wrap_content" > </com.example.listviewitemslidedeletebtnshow.QQListView></RelativeLayout>
接下来看看QQListView的实现:
package com.example.listviewitemslidedeletebtnshow;import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.PopupWindow;public class QQListView extends ListView {private static final String TAG = "QQlistView";// private static final int VELOCITY_SANP = 200; // private VelocityTracker mVelocityTracker; /*** 用户滑动的最小距离*/ private int touchSlop;/*** 是否响应滑动*/ private boolean isSliding;/*** 手指按下时的x坐标*/ private int xDown; /*** 手指按下时的y坐标*/ private int yDown; /*** 手指移动时的x坐标*/ private int xMove; /*** 手指移动时的y坐标*/ private int yMove;private LayoutInflater mInflater;private PopupWindow mPopupWindow; private int mPopupWindowHeight; private int mPopupWindowWidth;private Button mDelBtn; /*** 为删除按钮提供一个回调接口*/ private DelButtonClickListener mListener;/*** 当前手指触摸的View*/ private View mCurrentView;/*** 当前手指触摸的位置*/ private int mCurrentViewPos;/*** 必要的一些初始化** @param context* @param attrs*/ public QQListView(Context context, AttributeSet attrs) { super(context, attrs);mInflater = LayoutInflater.from(context); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();View view = mInflater.inflate(R.layout.delete_btn, null); mDelBtn = (Button) view.findViewById(R.id.id_item_btn); mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); /*** 先调用下measure,否则拿不到宽和高*/ mPopupWindow.getContentView().measure(0, 0); mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight(); mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth(); }@Override public boolean dispatchTouchEvent(MotionEvent ev) { int action = ev.getAction(); int x = (int) ev.getX(); int y = (int) ev.getY(); switch (action) {case MotionEvent.ACTION_DOWN: xDown = x; yDown = y; /*** 如果当前popupWindow显示,则直接隐藏,然后屏蔽ListView的touch事件的下传*/ if (mPopupWindow.isShowing()) { dismissPopWindow(); return false; } // 获得当前手指按下时的item的位置 mCurrentViewPos = pointToPosition(xDown, yDown); // 获得当前手指按下时的item View view = getChildAt(mCurrentViewPos - getFirstVisiblePosition()); mCurrentView = view; break; case MotionEvent.ACTION_MOVE: xMove = x; yMove = y; int dx = xMove - xDown; int dy = yMove - yDown; /*** 判断是否是从右到左的滑动*/ if (xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop) { // Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx + // " , dy = " + dy); isSliding = true; } break; } return super.dispatchTouchEvent(ev); }@Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); /*** 如果是从右到左的滑动才相应*/ if (isSliding) { switch (action) { case MotionEvent.ACTION_MOVE:int[] location = new int[2]; // 获得当前item的位置x与y mCurrentView.getLocationOnScreen(location); // 设置popupWindow的动画 mPopupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style); mPopupWindow.update(); mPopupWindow.showAtLocation(mCurrentView, Gravity.LEFT | Gravity.TOP, location[0] + mCurrentView.getWidth(), location[1] + mCurrentView.getHeight() / 2 - mPopupWindowHeight / 2); // 设置删除按钮的回调 mDelBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.clickHappend(mCurrentViewPos); mPopupWindow.dismiss(); } } }); // Log.e(TAG, "mPopupWindow.getHeight()=" + mPopupWindowHeight);break; case MotionEvent.ACTION_UP: isSliding = false;} // 相应滑动期间屏幕itemClick事件,避免发生冲突 return true; }return super.onTouchEvent(ev); }/*** 隐藏popupWindow*/ private void dismissPopWindow() { if (mPopupWindow != null && mPopupWindow.isShowing()) { mPopupWindow.dismiss(); } }public void setDelButtonClickListener(DelButtonClickListener listener) { mListener = listener; }interface DelButtonClickListener { public void clickHappend(int position); }} 代码注释写得很详细,简单说一下,在dispatchTouchEvent中设置当前是否响应用户滑动,然后在onTouchEvent中判断是否响应,如果响应则popupWindow以动画的形式展示出来。当然屏幕上如果存在PopupWindow则屏幕ListView的滚动与Item的点击,以及从右到左滑动时屏幕Item的click事件。
接下来是MainActivity.java,这里代码很简单不做介绍了。
package com.example.listviewitemslidedeletebtnshow;import java.util.ArrayList; import java.util.Arrays; import java.util.List;import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Toast;import com.example.listviewitemslidedeletebtnshow.QQListView.DelButtonClickListener;public class MainActivity extends Activity { private QQListView mListView; private ArrayAdapter<String> mAdapter; private List<String> mDatas;@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);mListView = (QQListView) findViewById(R.id.id_listview); // 不要直接Arrays.asList mDatas = new ArrayList<String>(Arrays.asList("HelloWorld", "Welcome", "Java", "Android", "Servlet", "Struts", "Hibernate", "Spring", "HTML5", "Javascript", "Lucene")); mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDatas); mListView.setAdapter(mAdapter);mListView.setDelButtonClickListener(new DelButtonClickListener() { @Override public void clickHappend(final int position) { Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show(); mAdapter.remove(mAdapter.getItem(position)); } });mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show(); } }); } } 效果图如下:楼主使用asm.jar以及gifcamera截的gif,由于button的动画很短感觉截图效果很卡不流畅,大家有什么好的截图,还望推荐。有兴趣的还是下载源码看看效果i。