工作中有时候会碰到需要列表侧滑删除的功能,在网上找了很多都需要定制listview列子,这在有些情况下会不太适合需求,所以我这里实现了一种值需要在列表中的item中使用这个控件的做法,与列表控件的自定义程度无关。,大家可以按照需求借鉴一下
惯例上图(注:侧滑有回弹效果哦):
public class MyScrollDeleteView extends ViewGroup {
private final Scroller scroller;
private final int slop;
private int leftBorder;
private int rightBorder;
private float mXDown;
private float mXLastMove;
private float mXMove;
public MyScrollDeleteView(Context context) {
this(context, null);
}
public MyScrollDeleteView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyScrollDeleteView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
scroller = new Scroller(context);
slop = ViewConfigurationCompat.getScaledPagingTouchSlop(ViewConfiguration.get(context));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
}
measureChild(getChildAt(0), widthMeasureSpec, heightMeasureSpec);
measureChild(getChildAt(1), widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
if (changed) {
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
getChildAt(0).layout(0, 0, getChildAt(0).getMeasuredWidth(), getChildAt(0).getMeasuredHeight());
getChildAt(1).layout(getChildAt(0).getMeasuredWidth(), 0, getChildAt(0).getMeasuredWidth() + getChildAt(1).getMeasuredWidth(), getChildAt(1).getMeasuredHeight());
leftBorder = getChildAt(0).getLeft();
rightBorder = getChildAt(childCount - 1).getRight();
// Toast.makeText(getContext(), leftBorder + "---" + rightBorder, Toast.LENGTH_SHORT).show();
}
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mXDown = ev.getRawX();
mXLastMove = mXDown;
break;
case MotionEvent.ACTION_MOVE:
mXMove = ev.getRawX();
float diff = Math.abs(mXMove - mXDown);
mXLastMove = mXMove;
//当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件
if (diff > slop) {
return true;
}
break;
} return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
mXMove = event.getRawX();
int scrolledX = (int) (mXLastMove - mXMove);
if (getScrollX() + scrolledX < leftBorder) {
scrollTo(leftBorder, 0);
return true;
} else if (getScrollX() + getWidth() + scrolledX > rightBorder) {
scrollTo(rightBorder - getWidth(), 0);
return true;
}
scrollBy(scrolledX, 0);
mXLastMove = mXMove;
break;
case MotionEvent.ACTION_UP:
//当手指抬起时,根据当前的滚动值来判定应该滚动到哪个子控件的界面
int targetIndex = (getScrollX() + getChildAt(1).getMeasuredWidth() / 2) / getChildAt(1).getMeasuredWidth();
int dx = targetIndex * getChildAt(1).getMeasuredWidth() - getScrollX();
//第二步,调用startScroll() 方法来初始化滚动数据并刷新界面
scroller.startScroll(getScrollX(), 0, dx, 0);
invalidate();
break;
} return super.onTouchEvent(event);
} /*如果是列表项,可以使用这个方法做初始化,delete按钮的视图重复,用法:在列表的adapter中做初始化*/
public void setScrollInit() {
scroller.startScroll(0, 0, 0, 0);
invalidate();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
//这里调用View的scrollTo() 完成实际的滚动
scrollTo (scroller.getCurrX(), scroller.getCurrY());
//必须调用该方法,否则不一定能看到滚动效果
invalidate ();
} super.computeScroll();
}
}
适配器Adapter代码:
private class MyAdapter extends BaseAdapter {
private Context context;
private List<String> dats;
public MyAdapter(Context context, List<String> dats) {
this.context = context;
this.dats = dats;
}
@Override
public int getCount() {
return dats.size();
}
@Override
public Object getItem(int i) {
return dats.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(final int i, View view, ViewGroup viewGroup) {
MyHolder holder=null;
if(view==null){
holder=new MyHolder();
view=View.inflate(context,R.layout.lv_item,null);
holder.tv_name=view.findViewById(R.id.tv_name);
holder.delete=view.findViewById(R.id.delete);
holder.item_parent=(MyScrollDeleteView)view.findViewById(R.id.item_parent);
view.setTag(holder);
}else{
holder= (MyHolder) view.getTag();
}
holder.item_parent.setScrollInit();
holder.tv_name.setText(mdatas.get(i));
holder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context,"hehe",Toast.LENGTH_SHORT).show();
delete(i);
}
});
holder.tv_name.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context,"xixi",Toast.LENGTH_SHORT).show();
}
});
return view;
}
public void delete(int pos){
dats.remove(pos);
notifyDataSetChanged();
}
}
private class MyHolder{
public TextView tv_name;
public TextView delete;
public MyScrollDeleteView item_parent;
}
子条目的布局代码:(建议大家在布局中指定MyScrollDeletview的高度,dp单位不影响适配)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.xuganwen.testui.MyScrollDeleteView
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/item_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/tv_name"
android:background="@android:color/holo_blue_bright"
/>
<TextView
android:layout_width="100dp"
android:layout_height="match_parent"
android:id="@+id/delete"
android:background="#6F00"
android:text="delete"/>
</com.xuganwen.testui.MyScrollDeleteView>
</LinearLayout>
//当使用列表listview时,需要避免滑动冲突,我这里使用的listview代码如下:就是根据滑动方向和距离的大小来判断到底是由listview还是由子条目来处理事件:
package com.hs.qianshubao.wealth.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView;
/**
* Created by aa on 2016/3/23.
*/
public class MyListview extends ListView {
public MyListview(Context context){
this(context,null);
}
public MyListview(Context context, AttributeSet attributeSet){
super(context,attributeSet);
}
public MyListview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, height);
}
private boolean flag=false;
private float downX=0;
private float downY=0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
downX=ev.getX();
downY=ev.getY();
//初始化 表明每次都是开始点击该控件
flag=false;
break;
case MotionEvent.ACTION_MOVE:
float x=ev.getX()-downX;
float y=ev.getY()-downY;
if(Math.abs(x)> Math.abs(y)){
flag=false;
}else{
flag=true;
}
// getParent().requestDisallowInterceptTouchEvent(!flag);
requestDisallowInterceptTouchEvent(!flag);
break;
case MotionEvent.ACTION_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
}
这只是一个简单的滚动效果,增加一下自己的技术栈,欢迎褒贬。