Back to project page SlideMenu.
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.
/* * 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(); } } }