侧滑删除菜单
1.正常初始化显示item的布局
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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="com.example.slidingmenu.MainActivity">
<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
item_main.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.slidingmenu.SlideLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp">
<include android:id="@+id/item_content" layout="@layout/item_content"/>
<include android:id="@+id/item_menu" layout="@layout/item_menu"/>
</com.example.slidingmenu.SlideLayout>
item_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:background="#22000000"
android:gravity="center"
android:text="Delete"
android:textColor="#ff0000"
android:textSize="25sp">
</TextView>
item_content.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#44000000"
android:gravity="center"
android:text="Content"
android:textColor="#000000"
android:textSize="25sp">
</TextView>
2.正常初始化显示item的代码实现
初始化控件
private View contentView;
private View menuView;
/**
* 当布局文件加载完成的时候回调这个方法
*/
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
contentView = getChildAt(0);
menuView = getChildAt(1);
}
得到content和menu的宽高
/**
* Content的宽
*/
private int contentWidth;
private int menuWidth;
private int viewHeight;// 他们的高都是相同的
在测量方法里,得到各个控件的高和宽
/**
* 在测量方法里,得到各个控件的高和宽
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
contentWidth = contentView.getMeasuredWidth();
menuWidth = menuView.getMeasuredWidth();
viewHeight = getMeasuredHeight();
}
计算位置,onLayout参数,为左上角的坐标和右下角的坐标
image@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
// 指定菜单的位置
menuView.layout(contentWidth, 0, contentWidth + menuWidth, viewHeight);
}
3.通过手势拖动打开或者关闭menu
1.在SildeLayout中重写onTouchEvent(),按下的时候记录初始坐标startX,Y,
2.在move的时候记录结束的坐标endX,Y,然后计算X轴的偏移量distacneX=endX-startX;通过Scrollto()方法对内容进行整体移动,而Scrollto()第一个参数为动态改变,第二个参数不变化,即int toScrollX = (int) (getScrollX() - distanceX);
3.屏蔽非法值
// 4.屏蔽非法值
if (toScrollX < 0)
{
toScrollX = 0;
}
else if (toScrollX > menuWidth)
{
toScrollX = menuWidth;
}
4.最后在move中对startX,Y重新赋值
startX = event.getX();
startY = event.getY();
5.具体代码
private float startX;
private float startY;
private float downX;// 只赋值一次
private float downY;
@Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
// 1.按下记录坐标
downX = startX = event.getX();
downY = startY = event.getY();
Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_MOVE");
// 2.记录结束值
float endX = event.getX();
float endY = event.getY();
// 3.计算偏移量
float distanceX = endX - startX;
int toScrollX = (int) (getScrollX() - distanceX);
// 4.屏蔽非法值
if (toScrollX < 0)
{
toScrollX = 0;
}
else if (toScrollX > menuWidth)
{
toScrollX = menuWidth;
}
scrollTo(toScrollX, getScrollY());
startX = event.getX();
startY = event.getY();
// 在X轴和Y轴滑动的距离
float DX = Math.abs(endX - downX);
float DY = Math.abs(endY - downY);
if (DX > DY && DX > 0)
{
// 水平方向滑动
// 响应侧滑
// 反拦截-事件给SlideLayout
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_UP");
int totalScrollX = getScrollX();// 偏移量
if (totalScrollX < menuWidth / 2)
{
// 关闭Menu
closeMenu();
}
else
{
// 打开Menu
openMenu();
}
break;
}
return true;
}
4.up时判断是平滑的打开还是关闭
int totalScrollX = getScrollX();// 偏移量
if (totalScrollX < menuWidth / 2)
{
// 关闭Menu
closeMenu();
}
else
{
// 打开Menu
openMenu();
}
/**
* 打开menu
*/
public void openMenu()
{
// --->menuWidth
int distanceX = menuWidth - getScrollX();
scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY());
invalidate();// 强制刷新
if (onStateChangeListenter != null)
{
onStateChangeListenter.onOpen(this);
}
}
/**
* 关闭menu
*/
public void closeMenu()
{
// --->0
int distanceX = 0 - getScrollX();
scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY());
invalidate();// 强制刷新
if (onStateChangeListenter != null)
{
onStateChangeListenter.onClose(this);
}
}
5.在ListView中显示侧滑item
1.初始化listview
private ListView lv_main;
private ArrayList<MyBean> myBeans;
private MyAdapter myAdapter;
private SlideLayout slideLayout;
private void initView()
{
lv_main = (ListView) findViewById(R.id.lv_main);
}
2.准备数据设置适配器
准备一个bean类,并提供一个带参的构造器,传递参数
/**
*
* @author: Hashub.NG
* @description:
* @update: 2018年8月1日 下午4:44:07
*/
public class MyBean
{
private String name;
public MyBean(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
准备数据并设置适配器
private void initData()
{
myBeans = new ArrayList<MyBean>();
for (int i = 0; i < 100; i++)
{
myBeans.add(new MyBean("Content" + i));
}
myAdapter = new MyAdapter();
lv_main.setAdapter(myAdapter);
}
适配器
class MyAdapter extends BaseAdapter
{
@Override
public int getCount()
{
return myBeans == null ? 0 : myBeans.size();
}
@Override
public Object getItem(int position)
{
return null;
}
@Override
public long getItemId(int position)
{
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent)
{
ViewHolder viewHolder;
if (convertView == null)
{
convertView = View.inflate(MainActivity.this, R.layout.item_main, null);
viewHolder = new ViewHolder();
viewHolder.item_content = (TextView) convertView.findViewById(R.id.item_content);
viewHolder.item_menu = (TextView) convertView.findViewById(R.id.item_menu);
convertView.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolder) convertView.getTag();
}
// 根据位置得到内容
final MyBean myBean = myBeans.get(position);
viewHolder.item_content.setText(myBean.getName());
viewHolder.item_content.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
MyBean myBean1 = myBeans.get(position);
Toast.makeText(MainActivity.this, myBean1.getName(), Toast.LENGTH_SHORT).show();
}
});
viewHolder.item_menu.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
SlideLayout slideLayout = (SlideLayout) v.getParent();
slideLayout.closeMenu();
myBeans.remove(myBean);
notifyDataSetChanged();
}
});
SlideLayout slideLayout = (SlideLayout) convertView;
slideLayout.setOnStateChangeListenter(new MyOnStateChangeListenter());
return convertView;
}
}
static class ViewHolder
{
TextView item_content;
TextView item_menu;
}
6.解决item滑动后不能自动打开和关闭
原因: ListView拦截事件并消费事件,导致up事件丢失
解决方法1:自定义一个listview返回一个false,传递事件给子view消费
解决方法2:在子view中请求发拦截,让父层把事件传递给自己,假如左右滑动距离大于8px,请求拦截
在SildeLayout的onTouchEvent()中
down的时候记录坐标
// 1.按下记录坐标
downX = startX = event.getX();
downY = startY = event.getY();
在move中计算距离并判断以及反拦截让自己处理处理
imageSlideLayout是ListView的下一层视图,所以反拦截-事件给SlideLayout
// 在X轴和Y轴滑动的距离
float DX = Math.abs(endX - downX);
float DY = Math.abs(endY - downY);
if (DX > DY && DX > 0)
{
// 水平方向滑动
// 响应侧滑
// 反拦截-事件给SlideLayout
getParent().requestDisallowInterceptTouchEvent(true);//请求拦截父层事件,即把父层的拦截事件干掉
}
7.解决内容视图设置点击事件时不能滑动item
imagecontentView把事件消费掉了,导致滑动无效,父层视图把子view的事件拦截即可,一般情况下,反拦截的优先级别高于拦截,此处子View没有反拦截,故可以父层拦截子view的事件。
在SlideLayout中拦截事件,但是不能全部拦截,滑动的时候才拦截,否则点击事件就不生效了。
/**
* true:拦截孩子的事件,但会执行当前控件的onTouchEvent()方法 false:不拦截孩子的事件,事件继续传递
*
* @param event
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
boolean intercept = false;
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
// 1.按下记录坐标
downX = startX = ev.getX();
Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_DOWN");
if (onStateChangeListenter != null)
{
onStateChangeListenter.onDown(this);
}
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_MOVE");
// 2.记录结束值
float endX = ev.getX();
float endY = ev.getY();
// 3.计算偏移量
float distanceX = endX - startX;
startX = ev.getX();
// 在X轴和Y轴滑动的距离
float DX = Math.abs(endX - downX);
if (DX > 8)
{
intercept = true;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return intercept;
}
在适配器中设置点击事件
viewHolder.item_content.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
MyBean myBean1 = myBeans.get(position);
Toast.makeText(MainActivity.this, myBean1.getName(), Toast.LENGTH_SHORT).show();
}
});
8.限制只能打开一个item
设置menu的点击事件
viewHolder.item_menu.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
SlideLayout slideLayout = (SlideLayout) v.getParent();
slideLayout.closeMenu();
myBeans.remove(myBean);
notifyDataSetChanged();
}
});
SlideLayout写接口监听状态变化
/**
* 监听SlideLayout状态的改变
*/
public interface OnStateChangeListenter
{
void onClose(SlideLayout layout);
void onDown(SlideLayout layout);
void onOpen(SlideLayout layout);
}
/**
* 设置SlideLayout状态的监听
*
* @param onStateChangeListenter
*/
public void setOnStateChangeListenter(OnStateChangeListenter onStateChangeListenter)
{
this.onStateChangeListenter = onStateChangeListenter;
}
MainActivity接口回调
slideLayout.setOnStateChangeListenter(new MyOnStateChangeListenter());
class MyOnStateChangeListenter implements SlideLayout.OnStateChangeListenter
{
@Override
public void onClose(SlideLayout layout)
{
if (slideLayout == layout)
{
slideLayout = null;
}
}
@Override
public void onDown(SlideLayout layout)
{
if (slideLayout != null && slideLayout != layout)
{
slideLayout.closeMenu();
}
}
@Override
public void onOpen(SlideLayout layout)
{
slideLayout = layout;
}
}
网友评论