렌더링:
인터넷에는 2개의 뷰가 합쳐져 있는데, 기본적으로 가로로 이동할 때는 오른쪽 뷰가 표시됩니다. 다만, QQ 최신 버전에서의 효과는 이렇지는 않지만 느낌이 매우 좋기 때문에 모방도가 높은 것을 사용하는 것이 좋습니다.
지식 포인트:
1. ViewDragHelper 사용
2. 사용자 정의된 뷰 그룹;
int dx, int dy): 뷰가 캡처되고 드래그 또는 설정으로 인해 위치가 변경됩니다
public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { viewDragHelper = ViewDragHelper.create(this, callback); } public boolean onInterceptTouchEvent(MotionEvent ev) { boolean result = viewDragHelper.shouldInterceptTouchEvent(ev); } public boolean onTouchEvent(MotionEvent event) { viewDragHelper.processTouchEvent(event); return true; }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <scrollviewgroup.lly.com.swiplayout.SwipeLayout android:id="@+id/swipeLayout" android:layout_width="match_parent" android:layout_height="wrap_content" > <!-- delete区域的布局 --> <include layout="@layout/layout_delete" /> <!-- item内容的布局 --> <include layout="@layout/layout_content" /> </scrollviewgroup.lly.com.swiplayout.SwipeLayout> </LinearLayout>
@Override protected void onFinishInflate() { super.onFinishInflate(); deleteView = getChildAt(0); contentView = getChildAt(1); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); deleteHeight = deleteView.getMeasuredHeight(); deleteWidth = deleteView.getMeasuredWidth(); contentWidth = contentView.getMeasuredWidth(); screenWidth = getWidth(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // super.onLayout(changed, left, top, right, bottom); deleteView.layout(screenWidth - deleteWidth, 0, (screenWidth - deleteWidth) + deleteWidth, deleteHeight); contentView.layout(0, 0, contentWidth, deleteHeight); }
public boolean onTouchEvent(MotionEvent event) { //如果当前有打开的,则下面的逻辑不能执行 if(!SwipeLayoutManager.getInstance().isShouldSwipe(this)){ requestDisallowInterceptTouchEvent(true); return true; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); break; case MotionEvent.ACTION_MOVE: //1.获取x和y方向移动的距离 float moveX = event.getX(); float moveY = event.getY(); float delatX = moveX - downX;//x方向移动的距离 float delatY = moveY - downY;//y方向移动的距离 if(Math.abs(delatX)>Math.abs(delatY)){ //表示移动是偏向于水平方向,那么应该SwipeLayout应该处理,请求父view不要拦截 requestDisallowInterceptTouchEvent(true); } //更新downX,downY downX = moveX; downY = moveY; break; case MotionEvent.ACTION_UP: break; } viewDragHelper.processTouchEvent(event); return true; }
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return child==contentView; } @Override public int getViewHorizontalDragRange(View child) { return deleteWidth; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if(child==contentView){ if(left>0)left = 0; if(left<-deleteWidth)left = -deleteWidth; } return left; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); //判断开和关闭的逻辑 if(contentView.getLeft()==0 && currentState!=SwipeState.Close){ //说明应该将state更改为关闭 currentState = SwipeState.Close; //回调接口关闭的方法 if(listener!=null){ listener.onClose(getTag()); } //说明当前的SwipeLayout已经关闭,需要让Manager清空一下 SwipeLayoutManager.getInstance().clearCurrentLayout(); }else if (contentView.getLeft()==-deleteWidth && currentState!=SwipeState.Open) { //说明应该将state更改为开 currentState = SwipeState.Open; //回调接口打开的方法 if(listener!=null){ listener.onOpen(getTag()); } //当前的Swipelayout已经打开,需要让Manager记录一下下 SwipeLayoutManager.getInstance().setSwipeLayout(SwipeLayout.this); } } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if(contentView.getLeft()<-deleteWidth/2){ //应该打开 open(); }else { //应该关闭 close(); } } };
/** * 打开的方法 */ public void open() { viewDragHelper.smoothSlideViewTo(contentView,-deleteWidth,contentView.getTop()); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } /** * 关闭的方法 */ public void close() { viewDragHelper.smoothSlideViewTo(contentView,0,contentView.getTop()); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); }; public void computeScroll() { if(viewDragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } }
recyView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if(dy>0 || dy<0){ SwipeLayoutManager.getInstance().closeCurrentLayout(); } } });
하루만 기다리세요.