實現了一個可側滑刪除的listView,這個view是一個繼承自listView的自定義view,
實現側滑刪除,可以通過很多種方式,今天我介紹的方式是通過PopupWindow的方式來實現的。
效果圖
效果圖1
效果圖2
思路
當一個listView在屏幕上顯示的時候,它上面(屏幕上面)發生的各種事件,我們是可以捕捉到的,我們只需要判斷一下是不是我們需要的事件,如果是的話,就產生反饋,對事件進行處理,否則就不處理即可。
當我們發現用戶是在一個item上面產生了滑動事件,并且是從右向左滑,并且滿足我們對有效滑動長度的定義的話,那么這次事件我們就判斷是有效的,我們就計算到相應的位置,并且產生相應的刪除的按鈕就可以了。
當我們發現用戶的單擊事件的時候,我們就讓刪除的按鈕消失就可以了。
實現思路來自于:鴻洋的博客
實現代碼
/**
* Created by linSir
* date at 2017/5/1.
* describe: listView,主要是實現可以側滑刪除
*/
public class MyListView extends ListView {
private static final String TAG = MyListView.class.getSimpleName();
private int touchSlop; //用戶滑動的最小距離
private boolean isSliding; //是否相應滑動
private int xDown; //按下的x坐標
private int yDown; //按下的y坐標
private int xMove; //手指移動時x的坐標
private int yMove; //手指移動是y的坐標
private LayoutInflater mInflater; //一個layoutInflater
private PopupWindow mPopupWindow; //彈出一個用于展示的popupWindow
private int mPopupWindowHeight; //該展示的popupWindow的高度
private int mPopupWindowWidth; //該展示的popupWindow的寬度
private TextView delete; //側滑后刪除的按鈕
private DeleteClickListener mListener; //點擊刪除后回調的接口
private View mCurrentView; //當前展示刪除按鈕的view
private int mCurrentViewPos; //當前展示刪除按鈕的view的位置(下標)
/**
* 該自定義view的構造方法
*/
public MyListView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mInflater = LayoutInflater.from(context); //一個Inflater
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); //最小的滑動距離
View view = mInflater.inflate(R.layout.delete_btn, null); //找到刪除按鈕的view
delete = (TextView) view.findViewById(R.id.delete); //找到刪除按鈕的控件
mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT); //彈出的popupWindow
mPopupWindow.getContentView().measure(0, 0); //初始化
mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight(); //獲取到該view的高度
mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth(); //獲取到該view的寬度
}
/**
* 觸摸事件的派發
*/
@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: //action_down 即點擊事件,這個時候需要關閉popupWindow
xDown = x;
yDown = y;
if (mPopupWindow.isShowing()) {
dismissPopWindow();
return false;
}
mCurrentViewPos = pointToPosition(xDown, yDown); //根據x,y坐標獲取到自己的下標
View view = getChildAt(mCurrentViewPos - getFirstVisiblePosition());//當前可見view的小標減去第一個可見的view的下標就可以找到當前的這個view
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) { //判斷向左滑動,并且滑動了一定距離
isSliding = true; //滿足這個條件就符合了打開的popupWindow的條件
}
break;
}
return super.dispatchTouchEvent(ev);
}
@Override public boolean onTouchEvent(MotionEvent ev) {
if (mCurrentView == null) { //判斷當前的view不存在之后,則直接return不進行處理這次時間
return false;
}
int action = ev.getAction();
if (isSliding) {
switch (action) {
case MotionEvent.ACTION_MOVE:
int[] location = new int[2];
mCurrentView.getLocationOnScreen(location);
mPopupWindow.update();
delete.setHeight(getMeasuredHeight()/getChildCount()); //計算出來每一個條目的高度
mPopupWindow.showAtLocation(mCurrentView, Gravity.LEFT | Gravity.TOP,
location[0] + mCurrentView.getWidth(), location[1] + mCurrentView.getHeight() / 2
- mPopupWindowHeight ); //設置顯示的位置
delete.setOnClickListener(new OnClickListener() {
@Override public void onClick(View view) {
if (mListener != null) {
mListener.onClickDelete(mCurrentViewPos);
mPopupWindow.dismiss();
}
}
});
break;
case MotionEvent.ACTION_UP:
isSliding = false;
break;
}
return true;
}
return super.onTouchEvent(ev);
}
private void dismissPopWindow() {
if (mPopupWindow != null && mPopupWindow.isShowing()) {
mPopupWindow.dismiss();
}
}
public void setDelButtonClickListener(DeleteClickListener listener) {
mListener = listener;
}
}
/**
* Created by linSir
* date at 2017/5/1.
* describe: 用于點擊刪除按鈕的回調
*/
public interface DeleteClickListener {
void onClickDelete(int position);
}
//測試用例
public class MainActivity extends AppCompatActivity {
private MyListView mListView;
private ArrayAdapter<String> mAdapter;
private List<String> mDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (MyListView) findViewById(R.id.id_listview);
mDatas = new ArrayList<String>(Arrays.asList("111", "222", "333", "444", "555", "666",
"777", "888", "999", "000"));
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDatas);
mListView.setAdapter(mAdapter);
mListView.setDelButtonClickListener(new DeleteClickListener() {
@Override public void onClickDelete(int position) {
Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), Toast.LENGTH_SHORT).show();
mAdapter.remove(mAdapter.getItem(position));
}
});
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), Toast.LENGTH_SHORT).show();
}
});
}
}
//主界面布局文件
<?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="match_parent"
android:orientation="vertical"
>
<com.dotengine.linsir.myrecyclerview.MyListView
android:id="@+id/id_listview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.dotengine.linsir.myrecyclerview.MyListView>
</LinearLayout>
//刪除按鈕的布局
<?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">
<TextView
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="刪除"
android:textSize="18sp"
android:gravity="center"
android:textColor="#FFF"
android:background="#b4f72626"
android:paddingLeft="12dp"
android:paddingRight="12dp"
/>
</LinearLayout>
以上便是這次分享的自定義view,最近一直在看自定義view,還有事件傳遞機制這里,也寫了很多測試程序,有空的時候會分享出來的~然后再強調一下,本文的全部思路來自于張鴻洋的博客。