效果圖
ScreenGif5.gif
- 滑動Recyclerview的時候自動關(guān)閉所有menu
- 拖動下一個menu的時候轴捎,自動關(guān)閉上一個menu
- 點(diǎn)擊編輯和刪除后,自動關(guān)閉menu
實現(xiàn)步驟
自定義一個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
主要是重新設(shè)置高度
@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占據(jù)全屏蚕脏,第二個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意圖侦副,進(jìn)行攔截
@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
處理彈性滑動,判斷什么時候要顯示菜單驼鞭,什么時候要關(guān)閉菜單
@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的時候為其監(jiān)聽滑動事件秦驯,在當(dāng)前有未關(guān)閉的菜單,并且滑動其他菜單的時候關(guān)閉上一個菜單终议,為刪除和編輯增加點(diǎn)擊事件
private SwipeMenu swipeMenu;
adapter = new CommonAdapter<String>(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滑動狀態(tài)發(fā)生改變時候汇竭,關(guān)閉所有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);
}
更新
上面的代碼侵入性較強(qiáng),需要Recyclerview和Adapter操作較多,使用一個static SwipMenu來實現(xiàn)侵入性較小的view
效果圖
ScreenGif6.gif
去掉了Recyclerview監(jiān)聽滑動狀態(tài)的代碼穴张,以及adapter中監(jiān)聽SwipeMenu滑動狀態(tài)细燎,去掉了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內(nèi)滑動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);
}
}
}
}
使用方法
只需要在合適的地方調(diào)用 SwipeMenu.closeMenu();
即可關(guān)閉菜單
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private CommonAdapter<String> adapter;
private List<String> 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<String>(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);
}
}