qq侧滑菜单的简单实现

疯了,疯了,刚刚写的一不小心被我删了 ,我就简单的把代码贴下,代码上面都有注释,
首先是布局文件,

<com.qianfeng.sideqq.ui.DragLayer xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mdragLayer"
    android:background="@drawable/bg"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/left_content"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#ff6600ff"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/iv_head"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/head" />

        <ListView
            android:id="@+id/lv_left"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </ListView>
    </LinearLayout>

    <com.qianfeng.sideqq.ui.MyLinearLayout
        android:id="@+id/my_linear"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
         android:background="#ffffff"
        android:orientation="vertical" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:paddingLeft="20dp" >

            <ImageView
                android:id="@+id/iv_main_head"
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_centerVertical="true"
                android:src="@drawable/head" />
        </RelativeLayout>

        <ListView
            android:id="@+id/lv_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </ListView>

    </com.qianfeng.sideqq.ui.MyLinearLayout>

</com.qianfeng.sideqq.ui.DragLayer>

自定义的两个控件,

/**
 * 自定义view 实现 拖动的效果
 * 
 * @author Administrator
 * 
 */
public class DragLayer extends FrameLayout {
    public DragLayer(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragLayer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private int mRange;
    private ViewDragHelper mDragHelper;
    private ViewGroup mleftLayout;
    private ViewGroup mMainLayout;
    private int windowWindth;
    private int windowHeight;
    private Status mStatus;


    public Status getStatus() {
        return mStatus;
    }

    public void setStatus(Status mStatus) {
        this.mStatus = mStatus;
    }

    private OnDragStatusChangeListener mlistener;
    // 定义的状态的枚举的  三种状态
    public static  enum Status{
        Open, Close,Draging;
    }
    public interface OnDragStatusChangeListener {
        // 状态打开的时候回调的方法
        void open();
        // 状态关闭的时候回调的方法
        void close();
        // 滑动的时候回调的方法
        void draging(float  percent);
    }
    public void setDragStatusListener(OnDragStatusChangeListener listener){
        this.mlistener=listener;

    }



    private void init() {
        // 参数1 是viewGroup 参数2 回调的接口,参数3 敏感度
        mDragHelper = ViewDragHelper.create(this, mCallback);
    }

    ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
        // 尝试捕获view的时候回调的方法
        @Override
        public boolean tryCaptureView(View arg0, int arg1) {
            // 返回true 表示的是 都可以进行滑动
            return true;

        }

        // 当capturedChild 被捕获成功的时候回调的方法
        public void onViewCaptured(View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
        }

        public int getViewHorizontalDragRange(View child) {
            // 获得View 横向被拖动的范围 ,但是值得注意的是,它不能决定拖拽的范围,仅仅决定了动画执行的速度
            return mRange;
        };

        // clamp 夹紧, 固定住 方法的作用是, 通过返回的int值,来确定view显示的地方
        // 参数1 正在滑动view 参数2
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child == mMainLayout) {
                left = getMoveDistance(left);
            }

            return left;
        }

        // 当changedView 的位置改变的时候回调的方法,处理要做的事情(更新状态,伴随动画,重绘界面)
        // 参数1 目前正在改变位置的view 参数2left 到x轴原点left的距离, 参数3top 到y轴的距离, 参数4dx
        // 表示的是速度还有方向,向左移动为正, 向右移动为负;
        // 参数5 同参数4
        public void onViewPositionChanged(View changedView, int left, int top,
                int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);

            int newleft = left;
            if (changedView == mleftLayout) {
                // 当滑动的view等于mleftLayout的时候 强制把 mleftLayout 重绘到屏幕的大小
                mleftLayout.layout(0, 0, windowWindth, windowHeight);
                newleft = mMainLayout.getLeft() + dx;
                newleft = getMoveDistance(newleft);
                // 把一个控件放到一个位置 , 位置有四个参数决定
                mMainLayout.layout(newleft, 0, newleft + windowWindth,
                        windowHeight);

            }
            dispatchEvent(newleft);
            // 为了 兼容低版本 手动调用绘制
            invalidate();

        };

        // 当view被释放的时候,执行动画,参数1 被释放的子view 参数2,水平方向上的速度 ,参数3 竖直方向上的速度
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            if (xvel == 0 && mMainLayout.getLeft() > mRange / 2.0f) {
                open();
            } else if (xvel > 0) {
                open();
            } else {
                close();
            }
        }

    };

    protected void dispatchEvent(int newleft) {
        // percent 的取值范围应该是从0-1
        float percent=newleft*1.0f/mRange;
        // 更新状态, 执行回调

        mStatus=UpdataStatus(percent);
        switch (mStatus) {
        //打开
        case Open:
            mlistener.open();
            break;
            // 关闭
        case Close:
            mlistener.close();
            break;
            // 滑动
        case Draging:
            mlistener.draging(percent);
            break;

        default:
            break;
        }
        //  测界面 的缩放的动画
//      mleftLayout.setScaleX(1-0.5f*percent);
//      mleftLayout.setScaleY(1-0.5f*percent);
        ViewHelper.setScaleX(mleftLayout,  (0.5f+0.5f*percent));
        ViewHelper.setScaleY(mleftLayout,  (0.5f+0.5f*percent));
        ViewHelper.setTranslationX(mleftLayout, evaluate(percent, -windowWindth/2.0f, 0));
        ViewHelper.setAlpha(mleftLayout, evaluate(percent,0.5f,1.0f));


        //主界面的缩放动画

        ViewHelper.setScaleX(mMainLayout,  evaluate(percent, 1.0f, 0.8f));
        ViewHelper.setScaleY(mMainLayout,  evaluate(percent, 1.0f, 0.8f));
    }
    // 更新状态的方法
    private Status UpdataStatus(float percent) {
        if (percent==0) {
            return Status.Close;
        }else if (percent==1.0f) {
            return Status.Open;
        }else {
            return Status.Draging;
        }


    }

    /**
     * 估值器
     * @param fraction
     * @param startValue
     * @param endValue
     * @return
     */
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }

    public void close() {
        close(true);
    }

    /**
     * 关闭的动画
     */
    public void close(boolean isSmooth) {
        // 是否平滑的关闭
        int finalLeft = 0;
        if (isSmooth) {
            // 如果返回的true 代表还没有移动到要移动位置,需要刷新下界面
            boolean flag = mDragHelper.smoothSlideViewTo(mMainLayout,
                    finalLeft, 0);
            if (flag) {
                ViewCompat.postInvalidateOnAnimation(DragLayer.this);
            }
        } else {
            mMainLayout.layout(finalLeft, 0, finalLeft + windowWindth,
                    windowHeight);
        }
    }

    public void open() {
        open(true);

    }

    /**
     * 打开的动画
     */
    public void open(boolean isSmooth) {
        // 是否平滑的关闭
        int finalLeft = mRange;
        if (isSmooth) {
            // 如果返回的true 代表还没有移动到要移动位置,需要刷新下界面
            boolean flag = mDragHelper.smoothSlideViewTo(mMainLayout,
                    finalLeft, 0);
            if (flag) {
                ViewCompat.postInvalidateOnAnimation(DragLayer.this);
            }
        } else {
            mMainLayout.layout(finalLeft, 0, finalLeft + windowWindth,
                    windowHeight);
        }
    }

    public void computeScroll() {
        super.computeScroll();
        // 是否持续平滑动作
        if (mDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    // 重写 父类的方法 ,让VIewDragHelper 去判断是否应该去 拦截事件
    public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragHelper.processTouchEvent(event);
        // 返回true 表示的是持续接受 触摸事件
        return true;
    }

    // 当xml文件 解析完毕之后,回调的方法
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        // 拿到两个控件的实例
        mleftLayout =  (ViewGroup) this.getChildAt(0);
        mMainLayout =  (ViewGroup) this.getChildAt(1);

    }

    // 当view的大小 改变的时候回调的方法 注意的是这个方法是执行在onMeasure(测量的方法) 方法 之后的
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 这里的getMeasuredWidth()和getWidth()方法 得到的值都是一样的
        windowWindth = getMeasuredWidth();
        windowHeight = getMeasuredHeight();
        // 滑动的距离
        mRange = (int) (0.6f * windowWindth);

    }

    private int getMoveDistance(int left) {
        if (left < 0) {
            return 0;
        } else if (left > mRange) {
            return mRange;
        }

        return left;
    }



}

自定义的linearLayer的类


public class MyLinearLayout  extends LinearLayout{

    private DragLayer mDragLayer;
    public MyLinearLayout(Context context) {
        super(context);
    }

    public MyLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    // 把 Draglayer 初始化 
    public void setDragLayer(DragLayer mDragLayer){
        this.mDragLayer=mDragLayer;
    }
    //  重写拦截事件的方法
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 如果当前是关闭状态
        if (mDragLayer.getStatus()==Status.Close) {

            return super.onInterceptTouchEvent(ev);
        }else {
            // 如果 状态是滑动 或者打开的状态 ,直接拦截事件
            return true;
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    if (mDragLayer.getStatus()==Status.Close) {

            return super.onTouchEvent(event);
        }else {
            // 如果 状态是滑动 或者打开的状态 ,直接拦截事件

            if (event.getAction()==MotionEvent.ACTION_UP) {
                mDragLayer.close();

            }
            return true;
        }


    }
}

Activity类的实现


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final DragLayer mDragLayer= (DragLayer) findViewById(R.id.mdragLayer);
        ListView mleftListView = (ListView) findViewById(R.id.lv_left);
        ListView mMainListView = (ListView) findViewById(R.id.lv_main);

        final MyLinearLayout myLinearLayout=    (MyLinearLayout) findViewById(R.id.my_linear);
        final ImageView iv_main_head=   (ImageView) findViewById(R.id.iv_main_head);
        final ImageView iv_left_head=(ImageView) findViewById(R.id.iv_head);


        myLinearLayout.setDragLayer(mDragLayer);
        iv_left_head.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 当 点击的时候让它 关闭右侧的菜单 ,显示 主界面
                mDragLayer.close();
            }
        });
        iv_main_head.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 打开 右侧的菜单
                mDragLayer.open();
            }
        });

        mleftListView.setAdapter(new ArrayAdapter<String>(this, 
                android.R.layout.simple_expandable_list_item_1,Cheeses.sCheeseStrings){
            @Override
            public View getView(int position, View convertView,
                    ViewGroup parent) {
                // 把textview的颜色改成 白色的 
                View view=super.getView(position, convertView, parent);
                TextView mTextView=(TextView)(view);
                mTextView.setTextColor(Color.WHITE);
                return view;
            }
        });

        mMainListView.setAdapter(new ArrayAdapter<String>(this, 
                android.R.layout.simple_expandable_list_item_1, Cheeses.NAMES));

        mDragLayer.setDragStatusListener(new OnDragStatusChangeListener() {

            @Override
            public void open() {
                System.out.println("sss"+"open");
            }


            @Override
            public void close() {
                // 当关闭的时候让 头像晃动
                System.out.println("sss"+"close");
//              TranslateAnimation translateAnimation
                // 参数1 动画添加到那个控件上 , 参数2 动画的名字 参数3 动画执行的范围
                ObjectAnimator animator=ObjectAnimator.ofFloat(iv_main_head, "translationX", 20);
                // 插补器  动态的改变 动画执行过程中的速度  等等   
                animator.setInterpolator(new CycleInterpolator(4));
                animator.setDuration(500);
                animator.start();
            }

            @Override
            public void draging(float percent) {
//              System.out.println("sss"+"draging");                
                float alpha=1.0f-percent;
                // 设置 透明度   当 正在滑动的时候 让iv_main_head 随着 滑动 而消失 或者显示
                ViewHelper.setAlpha(iv_main_head, alpha);

            }
        });

    }
}

还有一个就是ListView数据的具体实现类

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值