Androidはサイドスライド削除コントロールを実現し、Recyclerviewをサポートします.
13039 ワード
効果図
ScreenGif5.gif Recyclerviewをスライドさせると自動的にすべてのmenu を閉じる.次のmenuをドラッグすると、前のmenu が自動的に閉じる編集と削除をクリックすると、menu が自動的に閉じます.
実装手順
ビューグループをカスタマイズ
書き換えonMeasure
主に高さの再設定
onLayoutを書き直す
1つ目のviewをフルスクリーンに、2つ目のviewをメニューviewに
onInterruptTouchEventの書き換え
moveが2を超えると判断しmenuをドラッグする意図でブロックする
onTouchEventを書き換える
フレックススライドを処理し、メニューを表示するタイミング、メニューを閉じるタイミングを判断します
操作Recyclerview
SwipMenuをバインドするときにスライドイベントをリスニングし、現在閉じていないメニューがあり、他のメニューをスライドするときに前のメニューを閉じ、削除と編集のためにクリックイベントを追加します.
RecyclerViewスライド状態が変化した場合は、すべてのMenuをオフにします
SwipMenuコードアドレス
更新
上記のコードは侵入性が強く、RecyclerviewとAdapterの操作が多く必要であり、static SwipMenuを1つ使用して侵入性の小さいviewを実現する
効果図
ScreenGif6.gif
Recyclerviewリスニングスライド状態のコードを削除し、adapterでSwipeMenuリスニングスライド状態を削除し、SwipeMenuでブロックされたイベントのコードを削除します.
SwipeMenu
コードが少なく、使いやすい
使用方法
適切な場所で
完全なコード
ScreenGif5.gif
実装手順
ビューグループをカスタマイズ
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を書き直す
1つ目のviewをフルスクリーンに、2つ目の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を1つ使用して侵入性の小さいviewを実現する
効果図
ScreenGif6.gif
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);
}
}
完全なコード