效果图
- 滑动Recyclerview的时候自动关闭所有menu
- 拖动下一个menu的时候,自动关闭上一个menu
- 点击编辑和删除后,自动关闭menu
实现步骤
自定义一个ViewGroup
public class SwipeMenu extends ViewGroup
private int downX, moveX, moved;
private Scroller scroller = new Scroller(getContext());
private onScrollStateChanged onScrollStateChanged;
private boolean haveShowRight =false;
重写onMeasure
主要是重新设置高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
View child = getChildAt(0);
int margin =
((MarginLayoutParams) child.getLayoutParams()).topMargin +
((MarginLayoutParams) child.getLayoutParams()).bottomMargin;
setMeasuredDimension(width, getChildAt(0).getMeasuredHeight() + margin);
}
重写onLayout
让第一个view占据全屏,第二个view为菜单view
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
View child = getChildAt(i);
if (i == 0) {
child.layout(l, t, r, b);
} else if (i == 1) {
child.layout(r, t, r + child.getMeasuredWidth(), b);
}
}
}
重写onInterruptTouchEvent
判断move超过2为要拖动menu意图,进行拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) ev.getRawX();
break;
case MotionEvent.ACTION_MOVE:
moveX = (int) ev.getRawX();
if (moveX - downX > 2) {
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onInterceptTouchEvent(ev);
}
重写onTouchEvent
处理弹性滑动,判断什么时候要显示菜单,什么时候要关闭菜单
@Override
public boolean onTouchEvent(MotionEvent ev) {
if(!scroller.isFinished()){
return false;
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) ev.getRawX();
break;
case MotionEvent.ACTION_MOVE:
moveX = (int) ev.getRawX();
moved = moveX - downX;
if(haveShowRight){
moved-=getChildAt(1).getMeasuredWidth();
}
scrollTo(-moved, 0);
if (getScrollX() <= 0) {
scrollTo(0, 0);
} else if (getScrollX() >= getChildAt(1).getMeasuredWidth()) {
scrollTo(getChildAt(1).getMeasuredWidth(), 0);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if(getScrollX()>=getChildAt(1).getMeasuredWidth()/2){
haveShowRight = true;
smoothScrollTo(getChildAt(1).getMeasuredWidth(),0);
}else {
haveShowRight = false;
smoothScrollTo(0,0);
}
onScrollStateChanged.onScrollChanged(haveShowRight);
break;
}
return true;
}
操作Recyclerview
在绑定SwipMenu的时候为其监听滑动事件,在当前有未关闭的菜单,并且滑动其他菜单的时候关闭上一个菜单,为删除和编辑增加点击事件
private SwipeMenu swipeMenu;
adapter = new CommonAdapter(this, R.layout.item_test2, data) {
@Override
protected void convert(final ViewHolder holder, final String s, final int position) {
holder.setText(R.id.tv, s);
((SwipeMenu) holder.getView(R.id.vg)).setOnScrollStateChanged(new SwipeMenu.onScrollStateChanged() {
@Override
public void onScrollChanged(boolean haveShowRight) {
if(swipeMenu == holder.getView(R.id.vg)){
return;
}
closeAllMenu();
if(haveShowRight){
swipeMenu = holder.getView(R.id.vg);
}else {
swipeMenu = null;
}
}
});
holder.setOnClickListener(R.id.tv_del, new View.OnClickListener() {
@Override
public void onClick(View view) {
closeAllMenu();
Toast.makeText(MainActivity.this,"删除"+position,Toast.LENGTH_SHORT).show();
}
});
holder.setOnClickListener(R.id.tv_edit, new View.OnClickListener() {
@Override
public void onClick(View view) {
closeAllMenu();
Toast.makeText(MainActivity.this,"编辑"+position,Toast.LENGTH_SHORT).show();
}
});
}
};
private void closeAllMenu() {
if(swipeMenu !=null){
swipeMenu.closeMenu();
}
}
RecyclerView滑动状态发生改变时候,关闭所有Menu
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
closeAllMenu();
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
recyclerView.setAdapter(adapter);
}
SwipMenu代码地址
更新
上面的代码侵入性较强,需要Recyclerview和Adapter操作较多,使用一个static SwipMenu来实现侵入性较小的view
效果图
去掉了Recyclerview监听滑动状态的代码,以及adapter中监听SwipeMenu滑动状态,去掉了SwipeMenu中拦截事件的代码
SwipeMenu
代码更少,使用更方便
package com.administrator.customviewtest.successview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* Created by Administrator on 2017/6/27.
*/
public class SwipeMenu extends ViewGroup {
private int downX, moveX, moved;
private Scroller scroller = new Scroller(getContext());
private boolean haveShowRight = false;
public static SwipeMenu swipeMenu;
public SwipeMenu(Context context) {
super(context);
}
public SwipeMenu(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwipeMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (swipeMenu != null) {
swipeMenu.closeMenus();
swipeMenu = null;
}
}
//缓慢滚动到指定位置
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
//1000ms内滑动destX,效果就是慢慢滑动
scroller.startScroll(scrollX, 0, delta, 0, 100);
invalidate();
}
public void closeMenus() {
smoothScrollTo(0, 0);
haveShowRight = false;
}
public static void closeMenu() {
swipeMenu.closeMenus();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!scroller.isFinished()) {
return false;
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) ev.getRawX();
break;
case MotionEvent.ACTION_MOVE:
if (swipeMenu != null && swipeMenu == this && haveShowRight) {
closeMenu();
return true;
}
moveX = (int) ev.getRawX();
moved = moveX - downX;
if (haveShowRight) {
moved -= getChildAt(1).getMeasuredWidth();
}
scrollTo(-moved, 0);
if (getScrollX() <= 0) {
scrollTo(0, 0);
} else if (getScrollX() >= getChildAt(1).getMeasuredWidth()) {
scrollTo(getChildAt(1).getMeasuredWidth(), 0);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (swipeMenu != null) {
closeMenu();
}
if (getScrollX() >= getChildAt(1).getMeasuredWidth() / 2) {
haveShowRight = true;
swipeMenu = this;
smoothScrollTo(getChildAt(1).getMeasuredWidth(), 0);
} else {
haveShowRight = false;
smoothScrollTo(0, 0);
}
break;
}
return true;
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
View child = getChildAt(0);
int margin =
((MarginLayoutParams) child.getLayoutParams()).topMargin +
((MarginLayoutParams) child.getLayoutParams()).bottomMargin;
setMeasuredDimension(width, getChildAt(0).getMeasuredHeight() + margin);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
View child = getChildAt(i);
if (i == 0) {
child.layout(l, t, r, b);
} else if (i == 1) {
child.layout(r, t, r + child.getMeasuredWidth(), b);
}
}
}
}
使用方法
只需要在合适的地方调用 SwipeMenu.closeMenu();
即可关闭菜单
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private CommonAdapter adapter;
private List data = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9","10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = ((RecyclerView) findViewById(R.id.rv));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
adapter = new CommonAdapter(this, R.layout.item_test2, data) {
@Override
protected void convert(final ViewHolder holder, final String s, final int position) {
holder.setText(R.id.tv, s);
holder.setOnClickListener(R.id.tv_del, new View.OnClickListener() {
@Override
public void onClick(View view) {
SwipeMenu.closeMenu();
Toast.makeText(MainActivity.this,"删除"+position,Toast.LENGTH_SHORT).show();
}
});
holder.setOnClickListener(R.id.tv_edit, new View.OnClickListener() {
@Override
public void onClick(View view) {
SwipeMenu.closeMenu();
Toast.makeText(MainActivity.this,"编辑"+position,Toast.LENGTH_SHORT).show();
}
});
}
};
recyclerView.setAdapter(adapter);
}
}
完整代码