Android Open Source - SlideMenu Slide Menu






From Project

Back to project page SlideMenu.

License

The source code is released under:

Apache License

If you think the Android project SlideMenu listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2014 fengwx.cn@gmail.com
 */*from   ww w .  ja  v a 2  s .  c  om*/
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.fengwx.slidemenu;

import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

/**
 * SlideMenu widget
 * 
 * @author fengwx
 */
public class SlideMenu extends LinearLayout implements Configuration, SlideMenuManager {

  private VelocityTracker mVelocityTracker;

  private FrameLayout mLeftMenu;
  private ContentLayout mContent;
  private LayoutParams mLeftMenuParams;

  private int mScreenW;
  private int mLeftMenuLeftEdge, mLeftMenuRightEdge;
  private boolean mLeftMenuVisible;

  private float mDownX, mMoveX, mUpX;

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

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

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

  private void init() {
    // set layout attribute
    setOrientation(HORIZONTAL);
    mScreenW = getResources().getDisplayMetrics().widthPixels;

    // left
    mLeftMenu = new FrameLayout(getContext());
    addView(mLeftMenu);

    // content
    mContent = new ContentLayout(getContext());
    mContent.setOnTouchListener(mContentTouchListener);
    addView(mContent);
  }

  @Override
  public void setLeftMenuView(View view, LayoutParams params) {
    if (mLeftMenu.getChildCount() == 0) {
      mLeftMenuParams = params;
      if (params.width > mScreenW - LEFT_MENU_OFFSET || params.width == LayoutParams.MATCH_PARENT
          || params.width == LayoutParams.WRAP_CONTENT) {
        params.width = mScreenW - LEFT_MENU_OFFSET;
      }
      mLeftMenuLeftEdge = -params.width;
      mLeftMenuRightEdge = 0;
      mLeftMenuParams.leftMargin = mLeftMenuLeftEdge;
      mLeftMenu.setLayoutParams(mLeftMenuParams);
      mLeftMenu.addView(view);
      mContent.setLeftMenuW(-mLeftMenuLeftEdge);
    } else {
      throw new RuntimeException("The left view can be added once time.");
    }
  }

  @Override
  public void setContentView(View view, LayoutParams params) {
    if (mContent.getChildCount() == 0) {
      mContent.setLayoutParams(params);
      mContent.addView(view);
    } else {
      throw new RuntimeException("The content view can be added once time.");
    }
  }

  @Override
  public boolean isLeftMenuVisible() {
    return mLeftMenuVisible;
  }

  @Override
  public void toggle() {
    if (isLeftMenuVisible()) {
      smoothScrollToContent();
    } else {
      smoothScrollToLeftMenu();
    }
  }

  private OnTouchListener mContentTouchListener = new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      obtainVelocityTracker(event);
      switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
          mDownX = event.getRawX();
          break;
        case MotionEvent.ACTION_MOVE:
          // if down event is unreachable
          if (Float.compare(mDownX, 0.0f) == 0 || Float.compare(mDownX, mUpX) == 0) {
            mDownX = event.getRawX();
          }
          mMoveX = event.getRawX();
          int distanceX = (int) (mMoveX - mDownX);
          if (mLeftMenuVisible) {
            mLeftMenuParams.leftMargin = distanceX;
          } else {
            mLeftMenuParams.leftMargin = mLeftMenuLeftEdge + distanceX;
          }
          // deal with boundary
          if (mLeftMenuParams.leftMargin < mLeftMenuLeftEdge) {
            mLeftMenuParams.leftMargin = mLeftMenuLeftEdge;
          } else if (mLeftMenuParams.leftMargin > mLeftMenuRightEdge) {
            mLeftMenuParams.leftMargin = mLeftMenuRightEdge;
          }
          mLeftMenu.setLayoutParams(mLeftMenuParams);
          break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_OUTSIDE:
          mUpX = event.getRawX();
          if (canShowLeftMenu()) {
            if (canScrollToLeftMenu()) {
              smoothScrollToLeftMenu();
            } else {
              smoothScrollToContent();
            }
          } else if (canShowContent()) {
            if (canScrollToContent()) {
              smoothScrollToContent();
            } else {
              smoothScrollToLeftMenu();
            }
          }
          recycleVelocityTracker();
          mUpX = mDownX;
          break;
      }
      return true;
    }
  };

  /**
   * Create a new VelocityTracker
   * 
   * @param event
   */
  private void obtainVelocityTracker(MotionEvent event) {
    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(event);
  }

  /**
   * Retrieve the last computed X velocity
   * 
   * @return
   */
  private int getXVelocity() {
    mVelocityTracker.computeCurrentVelocity(VELOCITY_UNITS);
    int velocity = (int) mVelocityTracker.getXVelocity();
    return Math.abs(velocity);
  }

  /**
   * RecycleVelocityTracker
   */
  private void recycleVelocityTracker() {
    mVelocityTracker.recycle();
    mVelocityTracker = null;
  }

  /**
   * Judge whether can show content layout
   * 
   * @return
   */
  private boolean canShowContent() {
    return mUpX - mDownX < 0 && isLeftMenuVisible();
  }

  /**
   * Judge whether can show left menu layout
   * 
   * @return
   */
  private boolean canShowLeftMenu() {
    return mUpX - mDownX > 0 && !isLeftMenuVisible();
  }

  /**
   * Judge whether can scroll to left menu layout
   * 
   * @return
   */
  private boolean canScrollToLeftMenu() {
    return mUpX - mDownX > FINGER_MAX_DISTANCE_X / 2 || getXVelocity() > INSTANT_VELOCITY;
  }

  /**
   * Judge whether can scroll to content layout
   * 
   * @return
   */
  private boolean canScrollToContent() {
    return mDownX - mUpX > FINGER_MAX_DISTANCE_X / 2 || getXVelocity() > INSTANT_VELOCITY;
  }

  /**
   * Smooth scroll to left menu
   */
  private void smoothScrollToLeftMenu() {
    new SmoothScrollTask().execute(AUTO_SPEED);
  }

  /**
   * Smooth scroll to content
   */
  private void smoothScrollToContent() {
    new SmoothScrollTask().execute(-AUTO_SPEED);
  }

  class SmoothScrollTask extends AsyncTask<Integer, Integer, Integer> {
    @Override
    protected Integer doInBackground(Integer... speed) {
      int leftMargin = mLeftMenuParams.leftMargin;
      while (true) {
        leftMargin = leftMargin + speed[0];
        // deal with boundary
        if (leftMargin > mLeftMenuRightEdge) {
          leftMargin = mLeftMenuRightEdge;
          break;
        }
        if (leftMargin < mLeftMenuLeftEdge) {
          leftMargin = mLeftMenuLeftEdge;
          break;
        }
        publishProgress(leftMargin);
        sleep(20);
      }
      // set left menu visible
      if (speed[0] > 0) {
        mLeftMenuVisible = true;
      } else {
        mLeftMenuVisible = false;
      }
      mContent.setLeftMenuVisible(mLeftMenuVisible);
      return leftMargin;
    }

    @Override
    protected void onProgressUpdate(Integer... leftMargin) {
      mLeftMenuParams.leftMargin = leftMargin[0];
      mLeftMenu.setLayoutParams(mLeftMenuParams);
    }

    @Override
    protected void onPostExecute(Integer leftMargin) {
      mLeftMenuParams.leftMargin = leftMargin;
      mLeftMenu.setLayoutParams(mLeftMenuParams);
    }
  }

  private void sleep(long millis) {
    try {
      Thread.sleep(millis);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}




Java Source Code List

org.fengwx.SlideMenuActivity.java
org.fengwx.slidemenu.Configuration.java
org.fengwx.slidemenu.ContentLayout.java
org.fengwx.slidemenu.SlideMenuManager.java
org.fengwx.slidemenu.SlideMenu.java