自定义View:侧滑菜单实现

上篇博客咱们用动画实现了侧滑菜单,如果感兴趣可以通过传送门去看一下。今天咱们通过另一种方式实现侧滑菜单

一、布局

总布局


<com.yushan.slidemenu.SlideMenu xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/slideMenu"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include
        android:id="@+id/dl_secondary"
        layout="@layout/layout_secondary" />

    <include
        android:id="@+id/dl_main"
        layout="@layout/layout_main" />

com.yushan.slidemenu.SlideMenu>

这里的布局和动画实现的基本上没有区别,但是由于动画实现的SlidingMenu继承的是FrameLayout,而这次的SlidingMenu继承的是ViewGroup。所以样式如下:

自定义View:侧滑菜单实现_第1张图片

二、SlidingMenu实现

  • 重写构造方法
    public SlideMenu(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public SlideMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SlideMenu(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context) {
        scroller = new Scroller(context);
    }
  • 测量放置子控件
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        menuView = getChildAt(0);
        menuViewWidth = menuView.getLayoutParams().width;
        menuView.measure(menuViewWidth, heightMeasureSpec);

        mainView = getChildAt(1);
        mainView.measure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean bl, int l, int t, int r, int b) {
        menuView.layout(l - menuViewWidth, t, l, b);

        mainView.layout(l, t, r, b);
    }
  • 重写onTouchEvent方法
  @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                break;
            case MotionEvent.ACTION_MOVE:

                distanceY = event.getX() - downX;
                if (distanceY > 10) {
                    hasMove = true;
                } else {
                    hasMove = false;
                }

                if (distanceY < 0) {
                    distanceY = 0;
                } else if (distanceY > menuViewWidth) {
                    distanceY = menuViewWidth;
                }

                scrollTo((int) distanceY);
                break;
            case MotionEvent.ACTION_UP:
                if (hasMove) {
                    if (distanceY > menuViewWidth / 2) {
                        oldDistanceY = menuViewWidth;
                        mState = DragState.Open;
                    } else {
                        oldDistanceY = 0;
                        mState = DragState.Close;
                    }

                    int startX = (int) distanceY;
                    int destX = (int) oldDistanceY;

                    animationScroll(startX, destX);
                } else {
                    if (mState != DragState.Close) {
                        showMenu();
                    }
                }
                hasMove = false;
                break;
        }

        return true;
    }
  • 点击按钮显示/隐藏侧滑菜单
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.iv_menu:
                slideMenu.showMenu();
                break;
        }
    }

SlidingMenu中代码:

    /**
     * 方法功能:侧拉菜单的显示与隐藏
     */
    public void showMenu() {
        int startX;
        int destX;
        if (oldDistanceY > 0) {
            startX = menuViewWidth;
            destX = 0;
            mState = DragState.Close;
        } else {
            startX = 0;
            destX = menuViewWidth;
            mState = DragState.Open;
        }

        oldDistanceY = destX;
        animationScroll(startX, destX);
    }
  • 侧滑菜单的自动归位
    /**
     * 方法功能:自动归位
     *
     * @param startX
     * @param destX
     */
    private void animationScroll(int startX, int destX) {
        int distanceX = destX - startX;
        int startY = 0;
        int distanceY = 0;
        float maxDuration = 1000f;
        float maxMoveDistance = menuViewWidth;
        float scale = maxDuration / maxMoveDistance;
        int duration = (int) (Math.abs(distanceX) - scale);

        scroller.startScroll(startX, startY, distanceX, distanceY, duration);

        invalidate();
    }

这里道长用到了invalidate()这个方法重新绘制界面。但是需要注意的是:invalidate()方法不能直接在子线程中调用。Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。子线程中刷新界面可以通过Handler来通知UI线程调用invalidate()来进行界面更新。当然API提供了另一个方法来实现子线程中刷新界面的方法postInvalidate()。使用postInvalidate()刷新界面可以直接在子线程中调用postInvalidate()

到这里侧滑菜单就实现了,这种实现方式与侧滑菜单实现的最大的区别在于事件拦截操作方式,希望这篇博客可以给你提供一些帮助。下面是Demo的链接,如果需要可以去github下载

源码下载

SlidingMenu


你可能感兴趣的:(android-自定义控件)