自定义控件-侧拉菜单

来源:互联网 发布:编程工具与编程 编辑:程序博客网 时间:2024/05/16 13:42
    手机版qq有一个挺不错的效果是侧拉菜单,在主界面向右滑动就会在左侧出现关于自己qq的一些信息;
    实现侧滑效果目前知道有三种:
一是SlidingDrawer,谷歌在Android4.2之后已经不建议使用
二是DrawerLayout,谷歌提供的挺好用的控件,只需在布局文件中加载即可
三是第三方提供的开源控件,更加的灵活;下面就来简单介绍一下原理
  一、需求
    1.定义两个布局,菜单和主内容,然后整合在一个自定义的控件中
    2.分别测量出菜单和主内容的宽和高
    3.主内容全屏显示在屏幕上,那么左侧的菜单就会看不到,达到了隐藏菜单的效果
    4.处理屏幕的onTouchEvent()事件,实现左右滑动控制菜单的隐藏与显示
  二、具体实现
    1.定义布局文件菜单和主内容,然后整合在自定义的SlideMenu控件中
    2.在SlideMenu中通过onMeasure测量布局文件的宽和高
 @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //测量菜单的宽和高,宽为240dip,高为父窗体高度        //0代表菜单        View menuView = getChildAt(0);        menuView.measure(menuView.getLayoutParams().width, heightMeasureSpec);        //测量内容正文的宽和高,与父窗体一致        //1代表正文内容        View contentView = getChildAt(1);        contentView.measure(widthMeasureSpec, heightMeasureSpec);    }

        在系统底层measure调用了onMeasure(定义了宽高的约束)
onMeasrue调用了setMeasureDimension(真实的宽高信息)
    3.通过onLayout方法绘制布局
 @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        //把测量出菜单和内容绘制屏幕上        View menuView = getChildAt(0);        //设置菜单在屏幕的左侧显示(即隐藏)        menuView.layout(-menuView.getMeasuredWidth(), t, 0, b);        //主内容的绘制        View contentView = getChildAt(1);        contentView.layout(l, t, r, b);    }

    4.处理屏幕的onTouchEvent事件实现菜单的隐藏与显示
    @Override    public boolean onTouchEvent(MotionEvent event) {        int scrollX;        switch (event.getAction()) {            //按下            case MotionEvent.ACTION_DOWN:                downX = (int) event.getX();                break;            //移动            case MotionEvent.ACTION_MOVE:                int moveX = (int) event.getX();                //偏移量                int deltax = downX - moveX;                scrollX = getScrollX() + deltax;                //根据当前位置确定屏幕的显示                if (scrollX < -getChildAt(0).getMeasuredWidth()) {                    scrollTo(-getChildAt(0).getMeasuredWidth(), 0);                } else if (scrollX > 0) {                    scrollTo(0, 0);                } else {                    scrollBy(deltax, 0);                }                downX = moveX;                break;            //抬起            case MotionEvent.ACTION_UP:                int center = -getChildAt(0).getMeasuredWidth() / 2;                scrollX = getScrollX();                if (scrollX < center) {                    currentState = SCREEN_CONTENT;                } else {                    currentState = SCREEN_MAIN;                }                switchScreen();                break;        }        return true;    }    /**     * 根据currentState的状态来更改屏幕的显示     */    private void switchScreen() {        int startX = getScrollX();  //当前屏幕的X位置        int dX = 0;                 //增量=目的位置-当前位置        switch (currentState) {            case SCREEN_CONTENT://                scrollTo(-getChildAt(0).getMeasuredWidth(),0);                dX = -getChildAt(0).getMeasuredWidth() - startX;                break;            case SCREEN_MAIN://                scrollTo(0,0);                dX = 0 - startX;                break;        }        int duration = Math.abs(dX) * 10;        if (duration > 1000) {            duration = 1000;        }        scroller.startScroll(startX, 0, dX, 0, duration);        invalidate();    }    @Override    public void computeScroll() {        //当不在模拟数据时候跳出递归        if (scroller.computeScrollOffset()) {            //获取当前模拟的数据            int currX = scroller.getCurrX();            //更新位置            scrollTo(currX, 0);            invalidate();        }    }


       滑动的分析:
 1.当点击屏幕时记录下当前的位置downX,在移动的过程中根据当前位置moveX和downX计算偏移量
   根据偏移量的值不断的修正菜单和主内容在屏幕的显示位置;
         2.当抬起时,如果菜单显示出来的内容是否大于二分之一,那么滑动显示菜单,反之显示主内容
 3.currentState用来记录当前屏幕显示的是菜单还是主内容,并且是屏幕固定时偏移量计算的依据
 4.scroller.startScroll(startX,0,dX,0,duration)
   用来模拟X轴从startX到偏移dX经过duration时间的过程,但是这个方法只是模拟,并不会改变
   屏幕的显示,还需要通过invalidate()来修改屏幕的显示
 5.invalidate()在ViewGroup中通过调用DrawChild()->再调view.draw->computeScroll修改屏幕
   显示的内容,由于startScroll的数据是缓慢变化的,因此需要用递归不断的更新当前的显示,就
   实现了松手后菜单缓慢移动的效果
   三、回调简介
Android回调方法用的特别多,其原理类似于设计模式中的观察者模式,回调通过自身提供一个内部
接口,在接口定义统一的方法,那么不管是谁调用我,只要实现我接口中定义的方法,使代码有了很
好的封装性
   四、个人总结
写自定义控件一定要有的步骤:
1.分析控件的实现都有什么状态
2.找出状态之间转换的临界条件
3.实现即可
0 0
原创粉丝点击