首页 > 代码库 > 仿qq的条目抽屉动画效果_ViewDragHelper

仿qq的条目抽屉动画效果_ViewDragHelper

技术分享

GitHub地址:

  https://github.com/OOOOOldZhu/DrawerItemView

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;



public class SwipeLayout extends FrameLayout {

    private View content;
    private View delete;

    ViewDragHelper dragHelper;

    public SwipeLayout(Context context) {
        this(context, null);
    }

    public SwipeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        //初始化ViewDragHelper
        dragHelper = ViewDragHelper.create(this, callback);
    }
    //只有完成系统对xml文件完成最后标签的解析,才能获得子控件
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        content = getChildAt(0);
        delete = getChildAt(1);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        content.layout(0, 0, content.getMeasuredWidth(), 
            content.getMeasuredHeight());
        int L = content.getRight();  
        //content(右下角)的right(距原点的x距离)即为 delete控件的左上角的x坐标
        delete.layout(L, 0, L + delete.getMeasuredWidth(), 
            delete.getMeasuredHeight());
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
//让helper处理拦截事件
boolean result = dragHelper.shouldInterceptTouchEvent(ev); return result; } float downX,downY; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); //计算移动的距离 float dx = moveX - downX; float dy = moveY - downY; //判断到底偏向于哪个方向 if(Math.abs(dx)>Math.abs(dy)){ //说明是偏向水平方向,那么就认为用户想滑动条目,此时应该让listview不要拦截 requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: break; } dragHelper.processTouchEvent(event); return true; } // 回调方法 ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return true; } @Override public int getViewHorizontalDragRange(View child) { return 1; } //修正子控件的位置坐标的方法 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { //限制content if(child==content){ if(left>0){ left = 0; }else if(left<-delete.getMeasuredWidth()){ left = -delete.getMeasuredWidth(); } }else if(child==delete){ //限制delete if(left>content.getMeasuredWidth()){ left = content.getMeasuredWidth(); }else if(left<(content.getMeasuredWidth()- delete.getMeasuredWidth())) { left = (content.getMeasuredWidth()- delete.getMeasuredWidth()); } } return left; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); //如果移动的是content,那么让delete伴随移动 if(changedView==content){ // int newLeft = delete.getLeft()+dx; // delete.layout(newLeft,0,newLeft+delete.getMeasuredWidth(),delete.getMeasuredHeight()); ViewCompat.offsetLeftAndRight(delete,dx); }else if(changedView==delete){ //让content进行伴随移动 ViewCompat.offsetLeftAndRight(content,dx); } //回调接口的方法 if(listener!=null){ if(content.getLeft()==0){ listener.onClose(SwipeLayout.this); }else if(content.getLeft()==-delete.getMeasuredWidth()){ listener.onOpen(SwipeLayout.this); } } } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if(content.getLeft()>-delete.getMeasuredWidth()/2){ //关闭抽屉 closeLayout(); }else { //打开抽屉 openLayout(); } } }; /** * 打开 */ public void openLayout() { dragHelper.smoothSlideViewTo(content,-delete. getMeasuredWidth(),0); ViewCompat.postInvalidateOnAnimation(this); } /** * 关闭 */ public void closeLayout() { dragHelper.smoothSlideViewTo(content,0,0); ViewCompat.postInvalidateOnAnimation(this); } @Override public void computeScroll() { super.computeScroll(); if(dragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } } private OnSwipeListener listener; public void setOnSwipeListener(OnSwipeListener listener){ this.listener = listener; } public interface OnSwipeListener{ void onOpen(SwipeLayout currentLayout); void onClose(SwipeLayout currentLayout); } }

MainActivity中:

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import butterknife.Bind;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity {

    private ListView listview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listview = (ListView) findViewById(R.id.listview);

        listview.setAdapter(new MyAdapter());

        //监听listview的滚动
        listview.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if(openedLayout!=null){
                    openedLayout.closeLayout();
                }
            }
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, 
                int visibleItemCount, int totalItemCount) {
            }
        });

    }
    SwipeLayout openedLayout;//用来记录打开的SwipeLayout
    class MyAdapter extends BaseAdapter implements 
        SwipeLayout.OnSwipeListener{
        @Override
        public int getCount() {
            return Constant.NAMES.length;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            MyHolder myHolder = null;
            if(convertView==null){
                convertView = View.inflate(parent.getContext(), R.layout.adapter_list,
                    null);
                myHolder = new MyHolder(convertView);
                convertView.setTag(myHolder);
            }else {
                myHolder = (MyHolder) convertView.getTag();
            }

            //绑定数据
            myHolder.tvName.setText(Constant.NAMES[position]);

            //设置监听器
            myHolder.swipeLayout.setOnSwipeListener(this);

            return convertView;
        }
        @Override
        public void onOpen(SwipeLayout currentLayout) {
            //应该关闭当前已经打开的
            if(openedLayout!=null && openedLayout!=currentLayout){
                openedLayout.closeLayout();
            }

            openedLayout = currentLayout;
        }
        @Override
        public void onClose(SwipeLayout currentLayout) {
            if(openedLayout==currentLayout){
                openedLayout = null;
            }
        }
    }
    static class MyHolder {
        @Bind(R.id.tv_name)
        TextView tvName;
        @Bind(R.id.tv_delete)
        TextView tvDelete;
        @Bind(R.id.swipeLayout)
        SwipeLayout swipeLayout;

        MyHolder(View view) {
            ButterKnife.bind(this, view);

        }
    }
}

 

仿qq的条目抽屉动画效果_ViewDragHelper