Android 双侧侧滑菜单(主界面和菜单都会滑动)

来源:互联网 发布:网站排名优化查询 编辑:程序博客网 时间:2024/05/18 04:01

       转载请标明原地址:http://blog.csdn.net/gaolei1201/article/details/41121941

       最近公司刚开始做一个项目视频分享,主界面菜单需要实现两侧都是侧滑菜单,   现在我想实现效果如360手机助手,下面菜单也会滚动。github上有开源项目SlidingMenu,但是导入时会报错,主要是需要依赖ActionBarSherLock,经过本人修改后好用的SlidingMenu地址:http://download.csdn.net/detail/gaolei1201/9259839,但要命的是代码太复杂,为毛国外大牛都爱这样?!本人自己写的效果一样的简单版请参考:http://blog.csdn.net/gaolei1201/article/details/50404941


在网上又找到了一个例子,代码是精简过的,源码下载可访问  http://download.csdn.net/detail/j541205249/6286247   和http://download.csdn.net/download/wwj_748/8184889 效果图如下:

                           


效果是比较理想,但是它的左侧和右侧菜单宽度一样,而我们的项目需要左侧菜单窄,右边宽。需要修改一下,但实在是此例子难以理解,废了好大力气,实现了效果,但还是不太理想,有兴趣的朋友可以研究一下。本人做出来的效果如下图:



下面贴一些主要的代码


package com.kingdowin.gosu;import android.os.Bundle;import android.support.v4.app.FragmentTransaction;import android.util.DisplayMetrics;import android.view.View;import android.view.View.OnClickListener;import android.widget.ImageView;import com.kingdowin.gosu.util.slidingmenu.BaseSlidingFragmentActivity;import com.kingdowin.gosu.util.slidingmenu.SlidingMenu;public class MainActivity extends BaseSlidingFragmentActivity implementsOnClickListener {protected SlidingMenu mSlidingMenu;private LeftFragment mLeftFragment;private RightFragment mRightFragment;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initSlidingMenu();setContentView(R.layout.main_activity);initView(savedInstanceState);}private void initSlidingMenu() {DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);int mScreenWidth = dm.widthPixels;// 获取屏幕分辨率宽度// TODO Auto-generated method stubsetBehindContentView(R.layout.main_left_layout);// 设置左菜单FragmentTransaction mFragementTransaction = getSupportFragmentManager().beginTransaction();mLeftFragment = new LeftFragment();mFragementTransaction.replace(R.id.main_left_fragment, mLeftFragment);mFragementTransaction.commit();// customize the SlidingMenumSlidingMenu = getSlidingMenu();mSlidingMenu.setMode(SlidingMenu.LEFT_RIGHT);// 设置是左滑还是右滑,还是左右都可以滑,我这里左右都可以滑//mSlidingMenu.setShadowWidth(mScreenWidth / 60);// 设置阴影宽度<span style="color:#ff0000;">mSlidingMenu.setBehindOffset(mScreenWidth / 5);// 设置菜单宽度</span>mSlidingMenu.setFadeDegree(0.35f);// 设置淡入淡出的比例mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);//mSlidingMenu.setShadowDrawable(R.drawable.slidingmenu_shadow);// 设置左菜单阴影图片//mSlidingMenu.setSecondaryShadowDrawable(R.drawable.right_shadow);// 设置右菜单阴影图片mSlidingMenu.setFadeEnabled(true);// 设置滑动时菜单的是否淡入淡出mSlidingMenu.setBehindScrollScale(0.333f);// 设置滑动时拖拽效果}private void initView(Bundle savedInstanceState) {mSlidingMenu.setSecondaryMenu(R.layout.main_right_layout);FragmentTransaction mFragementTransaction = getSupportFragmentManager().beginTransaction();mRightFragment = new RightFragment();mFragementTransaction.replace(R.id.main_right_fragment, mRightFragment);mFragementTransaction.commit();// TODO Auto-generated method stub((ImageView) findViewById(R.id.left_menu_image)).setOnClickListener(this);((ImageView) findViewById(R.id.right_menu_image)).setOnClickListener(this);}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.left_menu_image:mSlidingMenu.showMenu(true);break;case R.id.right_menu_image:mSlidingMenu.showSecondaryMenu(true);break;default:break;}}}

如何让菜单变窄呢?且看这个类

package com.kingdowin.gosu.util.slidingmenu;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.util.Log;import android.util.TypedValue;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import com.kingdowin.gosu.R;import com.kingdowin.gosu.util.slidingmenu.SlidingMenu.CanvasTransformer;public class CustomViewBehind extends ViewGroup {private static final String TAG = "CustomViewBehind";private static final int MARGIN_THRESHOLD = 48; // dipsprivate int mTouchMode = SlidingMenu.TOUCHMODE_MARGIN;private CustomViewAbove mViewAbove;private View mContent;private View mSecondaryContent;private int mMarginThreshold;private int mWidthOffset;private CanvasTransformer mTransformer;private boolean mChildrenEnabled;public CustomViewBehind(Context context) {this(context, null);}public CustomViewBehind(Context context, AttributeSet attrs) {super(context, attrs);mMarginThreshold = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, MARGIN_THRESHOLD, getResources().getDisplayMetrics());}public void setCustomViewAbove(CustomViewAbove customViewAbove) {mViewAbove = customViewAbove;}public void setCanvasTransformer(CanvasTransformer t) {mTransformer = t;}public void setWidthOffset(int i) {mWidthOffset = i;requestLayout();}public int getBehindWidth() {return mContent.getWidth();}public void setContent(View v) {if (mContent != null)removeView(mContent);mContent = v;addView(mContent);}public View getContent() {return mContent;}/** * Sets the secondary (right) menu for use when setMode is called with * SlidingMenu.LEFT_RIGHT. *  * @param v *            the right menu */public void setSecondaryContent(View v) {if (mSecondaryContent != null)removeView(mSecondaryContent);mSecondaryContent = v;addView(mSecondaryContent);}public View getSecondaryContent() {return mSecondaryContent;}public void setChildrenEnabled(boolean enabled) {mChildrenEnabled = enabled;}@Overridepublic void scrollTo(int x, int y) {super.scrollTo(x, y);if (mTransformer != null)invalidate();}@Overridepublic boolean onInterceptTouchEvent(MotionEvent e) {return !mChildrenEnabled;}@Overridepublic boolean onTouchEvent(MotionEvent e) {return !mChildrenEnabled;}@Overrideprotected void dispatchDraw(Canvas canvas) {if (mTransformer != null) {canvas.save();mTransformer.transformCanvas(canvas, mViewAbove.getPercentOpen());super.dispatchDraw(canvas);canvas.restore();} elsesuper.dispatchDraw(canvas);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {final int width = r - l;final int height = b - t;mContent.layout(0, 0, width - mWidthOffset, height);if (mSecondaryContent != null)mSecondaryContent.layout(0, 0, width - mWidthOffset, height);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = getDefaultSize(0, widthMeasureSpec);int height = getDefaultSize(0, heightMeasureSpec);setMeasuredDimension(width, height);final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width- mWidthOffset);final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0,height);mContent.measure(contentWidth, contentHeight);if (mSecondaryContent != null)mSecondaryContent.measure(contentWidth, contentHeight);}private int mMode;private boolean mFadeEnabled;private final Paint mFadePaint = new Paint();private float mScrollScale;private Drawable mShadowDrawable;private Drawable mSecondaryShadowDrawable;private int mShadowWidth;private float mFadeDegree;public void setMode(int mode) {if (mode == SlidingMenu.LEFT || mode == SlidingMenu.RIGHT) {if (mContent != null)mContent.setVisibility(View.VISIBLE);if (mSecondaryContent != null)mSecondaryContent.setVisibility(View.INVISIBLE);}mMode = mode;}public int getMode() {return mMode;}public void setScrollScale(float scrollScale) {mScrollScale = scrollScale;}public float getScrollScale() {return mScrollScale;}public void setShadowDrawable(Drawable shadow) {mShadowDrawable = shadow;invalidate();}public void setSecondaryShadowDrawable(Drawable shadow) {mSecondaryShadowDrawable = shadow;invalidate();}public void setShadowWidth(int width) {mShadowWidth = width;invalidate();}public void setFadeEnabled(boolean b) {mFadeEnabled = b;}public void setFadeDegree(float degree) {if (degree > 1.0f || degree < 0.0f)throw new IllegalStateException("The BehindFadeDegree must be between 0.0f and 1.0f");mFadeDegree = degree;}public int getMenuPage(int page) {page = (page > 1) ? 2 : ((page < 1) ? 0 : page);if (mMode == SlidingMenu.LEFT && page > 1) {return 0;} else if (mMode == SlidingMenu.RIGHT && page < 1) {return 2;} else {return page;}}public void scrollBehindTo(View content, int x, int y) {int vis = View.VISIBLE;if (mMode == SlidingMenu.LEFT) {if (x >= content.getLeft())vis = View.INVISIBLE;scrollTo((int) ((x + getBehindWidth()) * mScrollScale), y);} else if (mMode == SlidingMenu.RIGHT) {if (x <= content.getLeft())vis = View.INVISIBLE;scrollTo((int) (getBehindWidth() - getWidth() + (x - getBehindWidth())* mScrollScale), y);} else if (mMode == SlidingMenu.LEFT_RIGHT) {mContent.setVisibility(x >= content.getLeft() ? View.INVISIBLE: View.VISIBLE);mSecondaryContent.setVisibility(x <= content.getLeft() ? View.INVISIBLE: View.VISIBLE);vis = x == 0 ? View.INVISIBLE : View.VISIBLE;if (x <= content.getLeft()) {scrollTo((int) ((x + getBehindWidth()) * mScrollScale), y);} else {scrollTo((int) (getBehindWidth() - getWidth() + (x - getBehindWidth())* mScrollScale), y);}}if (vis == View.INVISIBLE)Log.v(TAG, "behind INVISIBLE");setVisibility(vis);}public int getMenuLeft(View content, int page) {if (mMode == SlidingMenu.LEFT) {switch (page) {case 0:return content.getLeft() - getBehindWidth();case 2:return content.getLeft();}} else if (mMode == SlidingMenu.RIGHT) {switch (page) {case 0:return content.getLeft();case 2:return content.getLeft() + getBehindWidth();}} else if (mMode == SlidingMenu.LEFT_RIGHT) {switch (page) {case 0:Log.d("gaolei", "content.getLeft()-------0--------|"+content.getLeft());Log.d("gaolei", "getBehindWidth()-------0--------|"+getBehindWidth());//这行代码是把左侧菜单宽度减少270dpreturn content.getLeft() - getBehindWidth()+270;case 2:Log.d("gaolei", "content.getLeft()-------2--------|"+content.getLeft());Log.d("gaolei", "getBehindWidth()-------2--------|"+getBehindWidth());return content.getLeft() + getBehindWidth();}}return content.getLeft();}public int getAbsLeftBound(View content) {if (mMode == SlidingMenu.LEFT || mMode == SlidingMenu.LEFT_RIGHT) {return content.getLeft() - getBehindWidth();} else if (mMode == SlidingMenu.RIGHT) {return content.getLeft();}return 0;}public int getAbsRightBound(View content) {if (mMode == SlidingMenu.LEFT) {return content.getLeft();} else if (mMode == SlidingMenu.RIGHT|| mMode == SlidingMenu.LEFT_RIGHT) {return content.getLeft() + getBehindWidth();}return 0;}public boolean marginTouchAllowed(View content, int x) {int left = content.getLeft();int right = content.getRight();if (mMode == SlidingMenu.LEFT) {return (x >= left && x <= mMarginThreshold + left);} else if (mMode == SlidingMenu.RIGHT) {return (x <= right && x >= right - mMarginThreshold);} else if (mMode == SlidingMenu.LEFT_RIGHT) {return (x >= left && x <= mMarginThreshold + left)|| (x <= right && x >= right - mMarginThreshold);}return false;}public void setTouchMode(int i) {mTouchMode = i;}public boolean menuOpenTouchAllowed(View content, int currPage, float x) {switch (mTouchMode) {case SlidingMenu.TOUCHMODE_FULLSCREEN:return true;case SlidingMenu.TOUCHMODE_MARGIN:return menuTouchInQuickReturn(content, currPage, x);}return false;}public boolean menuTouchInQuickReturn(View content, int currPage, float x) {if (mMode == SlidingMenu.LEFT|| (mMode == SlidingMenu.LEFT_RIGHT && currPage == 0)) {return x >= content.getLeft();} else if (mMode == SlidingMenu.RIGHT|| (mMode == SlidingMenu.LEFT_RIGHT && currPage == 2)) {return x <= content.getRight();}return false;}public boolean menuClosedSlideAllowed(float dx) {if (mMode == SlidingMenu.LEFT) {return dx > 0;} else if (mMode == SlidingMenu.RIGHT) {return dx < 0;} else if (mMode == SlidingMenu.LEFT_RIGHT) {return true;}return false;}public boolean menuOpenSlideAllowed(float dx) {if (mMode == SlidingMenu.LEFT) {return dx < 0;} else if (mMode == SlidingMenu.RIGHT) {return dx > 0;} else if (mMode == SlidingMenu.LEFT_RIGHT) {return true;}return false;}<span style="color:#ff0000;">//注销掉这些代码,是去掉它的阴影和渐变效果</span>//public void drawShadow(View content, Canvas canvas) {//if (mShadowDrawable == null || mShadowWidth <= 0)//return;//int left = 0;//if (mMode == SlidingMenu.LEFT) {//left = content.getLeft() - mShadowWidth;//} else if (mMode == SlidingMenu.RIGHT) {//left = content.getRight();//} else if (mMode == SlidingMenu.LEFT_RIGHT) {//if (mSecondaryShadowDrawable != null) {//left = content.getRight();//mSecondaryShadowDrawable.setBounds(left, 0,//left + mShadowWidth, getHeight());//mSecondaryShadowDrawable.draw(canvas);//}//left = content.getLeft() - mShadowWidth;//}//mShadowDrawable.setBounds(left, 0, left + mShadowWidth, getHeight());//mShadowDrawable.draw(canvas);//}////public void drawFade(View content, Canvas canvas, float openPercent) {//if (!mFadeEnabled)//return;//final int alpha = (int) (mFadeDegree * 255 * Math.abs(1 - openPercent));//mFadePaint.setColor(Color.argb(alpha, 0, 0, 0));//int left = 0;//int right = 0;//if (mMode == SlidingMenu.LEFT) {//left = content.getLeft() - getBehindWidth();//right = content.getLeft();//} else if (mMode == SlidingMenu.RIGHT) {//left = content.getRight();//right = content.getRight() + getBehindWidth();//} else if (mMode == SlidingMenu.LEFT_RIGHT) {//left = content.getLeft() - getBehindWidth();//right = content.getLeft();//canvas.drawRect(left, 0, right, getHeight(), mFadePaint);//left = content.getRight();//right = content.getRight() + getBehindWidth();//}//canvas.drawRect(left, 0, right, getHeight(), mFadePaint);//}private boolean mSelectorEnabled = true;private Bitmap mSelectorDrawable;private View mSelectedView;public void drawSelector(View content, Canvas canvas, float openPercent) {if (!mSelectorEnabled)return;if (mSelectorDrawable != null && mSelectedView != null) {String tag = (String) mSelectedView.getTag(R.id.selected_view);if (tag.equals(TAG + "SelectedView")) {canvas.save();int left, right, offset;offset = (int) (mSelectorDrawable.getWidth() * openPercent);if (mMode == SlidingMenu.LEFT) {right = content.getLeft();left = right - offset;canvas.clipRect(left, 0, right, getHeight());canvas.drawBitmap(mSelectorDrawable, left,getSelectorTop(), null);} else if (mMode == SlidingMenu.RIGHT) {left = content.getRight();right = left + offset;canvas.clipRect(left, 0, right, getHeight());canvas.drawBitmap(mSelectorDrawable, right- mSelectorDrawable.getWidth(), getSelectorTop(),null);}canvas.restore();}}}public void setSelectorEnabled(boolean b) {mSelectorEnabled = b;}public void setSelectedView(View v) {if (mSelectedView != null) {mSelectedView.setTag(R.id.selected_view, null);mSelectedView = null;}if (v != null && v.getParent() != null) {mSelectedView = v;mSelectedView.setTag(R.id.selected_view, TAG + "SelectedView");invalidate();}}private int getSelectorTop() {int y = mSelectedView.getTop();y += (mSelectedView.getHeight() - mSelectorDrawable.getHeight()) / 2;return y;}public void setSelectorBitmap(Bitmap b) {mSelectorDrawable = b;refreshDrawableState();}}

但是左侧会有反弹效果,如果想去掉且看这个类

package com.kingdowin.gosu.util.slidingmenu;import java.util.ArrayList;import java.util.List;import com.kingdowin.gosu.util.slidingmenu.SlidingMenu.OnClosedListener;import com.kingdowin.gosu.util.slidingmenu.SlidingMenu.OnOpenedListener;import android.content.Context;import android.graphics.Canvas;import android.graphics.Rect;import android.os.Build;import android.support.v4.view.KeyEventCompat;import android.support.v4.view.MotionEventCompat;import android.support.v4.view.VelocityTrackerCompat;import android.support.v4.view.ViewCompat;import android.support.v4.view.ViewConfigurationCompat;import android.util.AttributeSet;import android.util.FloatMath;import android.util.Log;import android.view.FocusFinder;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.SoundEffectConstants;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.view.animation.Interpolator;import android.widget.Scroller;//import com.slidingmenu.lib.SlidingMenu.OnCloseListener;//import com.slidingmenu.lib.SlidingMenu.OnOpenListener;public class CustomViewAbove extends ViewGroup {private static final String TAG = "CustomViewAbove";private static final boolean DEBUG = true;private static final boolean USE_CACHE = false;private static final int MAX_SETTLE_DURATION = 600; // msprivate static final int MIN_DISTANCE_FOR_FLING = 25; // dipsprivate static final Interpolator sInterpolator = new Interpolator() {public float getInterpolation(float t) {t -= 1.0f;return t * t * t * t * t + 1.0f;}};private View mContent;private int mCurItem;private Scroller mScroller;private boolean mScrollingCacheEnabled;private boolean mScrolling;private boolean mIsBeingDragged;private boolean mIsUnableToDrag;private int mTouchSlop;private float mInitialMotionX;/** * Position of the last motion event. */private float mLastMotionX;private float mLastMotionY;/** * ID of the active pointer. This is used to retain consistency during * drags/flings if multiple pointers are used. */protected int mActivePointerId = INVALID_POINTER;/** * Sentinel value for no current active pointer. * Used by {@link #mActivePointerId}. */private static final int INVALID_POINTER = -1;/** * Determines speed during touch scrolling */protected VelocityTracker mVelocityTracker;private int mMinimumVelocity;protected int mMaximumVelocity;private int mFlingDistance;private CustomViewBehind mViewBehind;//private int mMode;private boolean mEnabled = true;private OnPageChangeListener mOnPageChangeListener;private OnPageChangeListener mInternalPageChangeListener;//private OnCloseListener mCloseListener;//private OnOpenListener mOpenListener;private OnClosedListener mClosedListener;private OnOpenedListener mOpenedListener;private List<View> mIgnoredViews = new ArrayList<View>();//private int mScrollState = SCROLL_STATE_IDLE;/** * Callback interface for responding to changing state of the selected page. */public interface OnPageChangeListener {/** * This method will be invoked when the current page is scrolled, either as part * of a programmatically initiated smooth scroll or a user initiated touch scroll. * * @param position Position index of the first page currently being displayed. *                 Page position+1 will be visible if positionOffset is nonzero. * @param positionOffset Value from [0, 1) indicating the offset from the page at position. * @param positionOffsetPixels Value in pixels indicating the offset from position. */public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);/** * This method will be invoked when a new page becomes selected. Animation is not * necessarily complete. * * @param position Position index of the new selected page. */public void onPageSelected(int position);}/** * Simple implementation of the {@link OnPageChangeListener} interface with stub * implementations of each method. Extend this if you do not intend to override * every method of {@link OnPageChangeListener}. */public static class SimpleOnPageChangeListener implements OnPageChangeListener {public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {// This space for rent}public void onPageSelected(int position) {// This space for rent}public void onPageScrollStateChanged(int state) {// This space for rent}}public CustomViewAbove(Context context) {this(context, null);}public CustomViewAbove(Context context, AttributeSet attrs) {super(context, attrs);initCustomViewAbove();}void initCustomViewAbove() {//setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);setClickable(true);setFocusable(true);setWillNotDraw(false);final Context context = getContext();mScroller = new Scroller(context, sInterpolator);final ViewConfiguration configuration = ViewConfiguration.get(context);mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();setInternalPageChangeListener(new SimpleOnPageChangeListener() {public void onPageSelected(int position) {if (mViewBehind != null) {switch (position) {case 0:case 2:mViewBehind.setChildrenEnabled(true);break;case 1:mViewBehind.setChildrenEnabled(false);break;}}}});final float density = context.getResources().getDisplayMetrics().density;mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);}/** * Set the currently selected page. If the CustomViewPager has already been through its first * layout there will be a smooth animated transition between the current item and the * specified item. * * @param item Item index to select */public void setCurrentItem(int item) {setCurrentItemInternal(item, true, false);}/** * Set the currently selected page. * * @param item Item index to select * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately */public void setCurrentItem(int item, boolean smoothScroll) {setCurrentItemInternal(item, smoothScroll, false);}public int getCurrentItem() {return mCurItem;}void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {setCurrentItemInternal(item, smoothScroll, always, 0);}void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {if (!always && mCurItem == item) {setScrollingCacheEnabled(false);return;}item = mViewBehind.getMenuPage(item);final boolean dispatchSelected = mCurItem != item;mCurItem = item;final int destX = getDestScrollX(mCurItem);Log.d("gaolei","destX------------------||"+ destX);if (dispatchSelected && mOnPageChangeListener != null) {mOnPageChangeListener.onPageSelected(item);}if (dispatchSelected && mInternalPageChangeListener != null) {mInternalPageChangeListener.onPageSelected(item);}if (smoothScroll) {smoothScrollTo(destX, 0, velocity);} else {completeScroll();scrollTo(destX, 0);}}/** * Set a listener that will be invoked whenever the page changes or is incrementally * scrolled. See {@link OnPageChangeListener}. * * @param listener Listener to set */public void setOnPageChangeListener(OnPageChangeListener listener) {mOnPageChangeListener = listener;}/*public void setOnOpenListener(OnOpenListener l) {mOpenListener = l;}public void setOnCloseListener(OnCloseListener l) {mCloseListener = l;} */public void setOnOpenedListener(OnOpenedListener l) {mOpenedListener = l;}public void setOnClosedListener(OnClosedListener l) {mClosedListener = l;}/** * Set a separate OnPageChangeListener for internal use by the support library. * * @param listener Listener to set * @return The old listener that was set, if any. */OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {OnPageChangeListener oldListener = mInternalPageChangeListener;mInternalPageChangeListener = listener;return oldListener;}public void addIgnoredView(View v) {if (!mIgnoredViews.contains(v)) {mIgnoredViews.add(v);}}public void removeIgnoredView(View v) {mIgnoredViews.remove(v);}public void clearIgnoredViews() {mIgnoredViews.clear();}// We want the duration of the page snap animation to be influenced by the distance that// the screen has to travel, however, we don't want this duration to be effected in a// purely linear fashion. Instead, we use this method to moderate the effect that the distance// of travel has on the overall snap duration.float distanceInfluenceForSnapDuration(float f) {f -= 0.5f; // center the values about 0.f *= 0.3f * Math.PI / 2.0f;return (float) FloatMath.sin(f);}public int getDestScrollX(int page) {switch (page) {case 0:case 2:return mViewBehind.getMenuLeft(mContent, page);case 1:return mContent.getLeft();}return 0;}private int getLeftBound() {return mViewBehind.getAbsLeftBound(mContent);}private int getRightBound() {return mViewBehind.getAbsRightBound(mContent);}public int getContentLeft() {return mContent.getLeft() + mContent.getPaddingLeft();}public boolean isMenuOpen() {return mCurItem == 0 || mCurItem == 2;}private boolean isInIgnoredView(MotionEvent ev) {Rect rect = new Rect();for (View v : mIgnoredViews) {v.getHitRect(rect);if (rect.contains((int)ev.getX(), (int)ev.getY())) return true;}return false;}public int getBehindWidth() {if (mViewBehind == null) {return 0;} else {return mViewBehind.getBehindWidth();}}public int getChildWidth(int i) {switch (i) {case 0:return getBehindWidth();case 1:return mContent.getWidth();default:return 0;}}public boolean isSlidingEnabled() {return mEnabled;}public void setSlidingEnabled(boolean b) {mEnabled = b;}/** * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. * * @param x the number of pixels to scroll by on the X axis * @param y the number of pixels to scroll by on the Y axis */void smoothScrollTo(int x, int y) {smoothScrollTo(x, y, 0);}/** * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. * * @param x the number of pixels to scroll by on the X axis * @param y the number of pixels to scroll by on the Y axis * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) */void smoothScrollTo(int x, int y, int velocity) {if (getChildCount() == 0) {// Nothing to do.setScrollingCacheEnabled(false);return;}int sx = getScrollX();int sy = getScrollY();int dx = x - sx;int dy = y - sy;if (dx == 0 && dy == 0) {completeScroll();if (isMenuOpen()) {if (mOpenedListener != null)mOpenedListener.onOpened();} else {if (mClosedListener != null)mClosedListener.onClosed();}return;}setScrollingCacheEnabled(true);mScrolling = true;final int width = getBehindWidth();final int halfWidth = width / 2;final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);final float distance = halfWidth + halfWidth *distanceInfluenceForSnapDuration(distanceRatio);int duration = 0;velocity = Math.abs(velocity);if (velocity > 0) {duration = 4 * Math.round(1000 * Math.abs(distance / velocity));} else {final float pageDelta = (float) Math.abs(dx) / width;duration = (int) ((pageDelta + 1) * 100);duration = MAX_SETTLE_DURATION;}duration = Math.min(duration, MAX_SETTLE_DURATION);mScroller.startScroll(sx, sy, dx, dy, duration);invalidate();}public void setContent(View v) {if (mContent != null) this.removeView(mContent);mContent = v;//mContent.setClickable(true);mContent.setFocusable(true);addView(mContent);}public View getContent() {return mContent;}public void setCustomViewBehind(CustomViewBehind cvb) {mViewBehind = cvb;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = getDefaultSize(0, widthMeasureSpec);int height = getDefaultSize(0, heightMeasureSpec);setMeasuredDimension(width, height);final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);mContent.measure(contentWidth, contentHeight);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);// Make sure scroll position is set correctly.if (w != oldw) {// [ChrisJ] - This fixes the onConfiguration change for orientation issue..// maybe worth having a look why the recomputeScroll pos is screwing// up?completeScroll();scrollTo(getDestScrollX(mCurItem), getScrollY());}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {final int width = r - l;final int height = b - t;mContent.layout(0, 0, width, height);}public void setAboveOffset(int i) {//RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams)mContent.getLayoutParams());//params.setMargins(i, params.topMargin, params.rightMargin, params.bottomMargin);mContent.setPadding(i, mContent.getPaddingTop(), mContent.getPaddingRight(), mContent.getPaddingBottom());}@Overridepublic void computeScroll() {if (!mScroller.isFinished()) {if (mScroller.computeScrollOffset()) {int oldX = getScrollX();int oldY = getScrollY();int x = mScroller.getCurrX();int y = mScroller.getCurrY();if (oldX != x || oldY != y) {scrollTo(x, y);pageScrolled(x);}// Keep on drawing until the animation has finished.invalidate();return;}}// Done with scroll, clean up state.completeScroll();}private void pageScrolled(int xpos) {final int widthWithMargin = getWidth();final int position = xpos / widthWithMargin;final int offsetPixels = xpos % widthWithMargin;final float offset = (float) offsetPixels / widthWithMargin;onPageScrolled(position, offset, offsetPixels);}/** * This method will be invoked when the current page is scrolled, either as part * of a programmatically initiated smooth scroll or a user initiated touch scroll. * If you override this method you must call through to the superclass implementation * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled * returns. * * @param position Position index of the first page currently being displayed. *                 Page position+1 will be visible if positionOffset is nonzero. * @param offset Value from [0, 1) indicating the offset from the page at position. * @param offsetPixels Value in pixels indicating the offset from position. */protected void onPageScrolled(int position, float offset, int offsetPixels) {if (mOnPageChangeListener != null) {mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);}if (mInternalPageChangeListener != null) {mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);}}private void completeScroll() {boolean needPopulate = mScrolling;if (needPopulate) {// Done with scroll, no longer want to cache view drawing.setScrollingCacheEnabled(false);mScroller.abortAnimation();int oldX = getScrollX();int oldY = getScrollY();int x = mScroller.getCurrX();int y = mScroller.getCurrY();if (oldX != x || oldY != y) {scrollTo(x, y);}if (isMenuOpen()) {if (mOpenedListener != null)mOpenedListener.onOpened();} else {if (mClosedListener != null)mClosedListener.onClosed();}}mScrolling = false;}protected int mTouchMode = SlidingMenu.TOUCHMODE_MARGIN;public void setTouchMode(int i) {mTouchMode = i;}public int getTouchMode() {return mTouchMode;}private boolean thisTouchAllowed(MotionEvent ev) {int x = (int) (ev.getX() + mScrollX);if (isMenuOpen()) {return mViewBehind.menuOpenTouchAllowed(mContent, mCurItem, x);} else {switch (mTouchMode) {case SlidingMenu.TOUCHMODE_FULLSCREEN:return !isInIgnoredView(ev);case SlidingMenu.TOUCHMODE_NONE:return false;case SlidingMenu.TOUCHMODE_MARGIN:return mViewBehind.marginTouchAllowed(mContent, x);}}return false;}private boolean thisSlideAllowed(float dx) {boolean allowed = false;if (isMenuOpen()) {allowed = mViewBehind.menuOpenSlideAllowed(dx);} else {allowed = mViewBehind.menuClosedSlideAllowed(dx);}if (DEBUG)Log.v(TAG, "this slide allowed " + allowed + " dx: " + dx);return allowed;}private int getPointerIndex(MotionEvent ev, int id) {int activePointerIndex = MotionEventCompat.findPointerIndex(ev, id);if (activePointerIndex == -1)mActivePointerId = INVALID_POINTER;return activePointerIndex;}private boolean mQuickReturn = false;@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (!mEnabled)return false;final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;if (action == MotionEvent.ACTION_DOWN && DEBUG)Log.v(TAG, "Received ACTION_DOWN");if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP|| (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) {endDrag();return false;}switch (action) {case MotionEvent.ACTION_MOVE:try{final int activePointerId = mActivePointerId;if (activePointerId == INVALID_POINTER)break;final int pointerIndex = this.getPointerIndex(ev, activePointerId);final float x = MotionEventCompat.getX(ev, pointerIndex);final float dx = x - mLastMotionX;final float xDiff = Math.abs(dx);final float y = MotionEventCompat.getY(ev, pointerIndex);final float yDiff = Math.abs(y - mLastMotionY);if (DEBUG) Log.v(TAG, "onInterceptTouch moved to:(" + x + ", " + y + "), diff:(" + xDiff + ", " + yDiff + "), mLastMotionX:" + mLastMotionX);if (xDiff > mTouchSlop && xDiff > yDiff && thisSlideAllowed(dx)) {if (DEBUG) Log.v(TAG, "Starting drag! from onInterceptTouch");startDrag();mLastMotionX = x;setScrollingCacheEnabled(true);} else if (yDiff > mTouchSlop) {mIsUnableToDrag = true;}}catch(IllegalArgumentException e){e.printStackTrace();}break;case MotionEvent.ACTION_DOWN:mActivePointerId = ev.getAction() & ((Build.VERSION.SDK_INT >= 8) ? MotionEvent.ACTION_POINTER_INDEX_MASK : MotionEvent.ACTION_POINTER_INDEX_MASK);mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, mActivePointerId);mLastMotionY = MotionEventCompat.getY(ev, mActivePointerId);if (thisTouchAllowed(ev)) {mIsBeingDragged = false;mIsUnableToDrag = false;if (isMenuOpen() && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {mQuickReturn = true;}} else {mIsUnableToDrag = true;}break;case MotionEventCompat.ACTION_POINTER_UP:onSecondaryPointerUp(ev);break;}if (!mIsBeingDragged) {if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(ev);}return mIsBeingDragged || mQuickReturn;}@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (!mEnabled)return false;//if (!mIsBeingDragged && !thisTouchAllowed(ev))//return false;if (!mIsBeingDragged && !mQuickReturn)return false;final int action = ev.getAction();if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}mVelocityTracker.addMovement(ev);switch (action & MotionEventCompat.ACTION_MASK) {case MotionEvent.ACTION_DOWN:/* * If being flinged and user touches, stop the fling. isFinished * will be false if being flinged. */completeScroll();// Remember where the motion event startedmLastMotionX = mInitialMotionX = ev.getX();mActivePointerId = MotionEventCompat.getPointerId(ev, 0);break;case MotionEvent.ACTION_MOVE:if (!mIsBeingDragged) {if (mActivePointerId == INVALID_POINTER)break;final int pointerIndex = getPointerIndex(ev, mActivePointerId);final float x = MotionEventCompat.getX(ev, pointerIndex);final float dx = x - mLastMotionX;final float xDiff = Math.abs(dx);final float y = MotionEventCompat.getY(ev, pointerIndex);final float yDiff = Math.abs(y - mLastMotionY);if (DEBUG) Log.v(TAG, "onTouch moved to:(" + x + ", " + y + "), diff:(" + xDiff + ", " + yDiff + ")\nmIsBeingDragged:" + mIsBeingDragged + ", mLastMotionX:" + mLastMotionX);if ((xDiff > mTouchSlop || (mQuickReturn && xDiff > mTouchSlop / 4))&& xDiff > yDiff && thisSlideAllowed(dx)) {if (DEBUG) Log.v(TAG, "Starting drag! from onTouch");startDrag();mLastMotionX = x;setScrollingCacheEnabled(true);} else {if (DEBUG) Log.v(TAG, "onTouch returning false");return false;}}<span style="color:#ff0000;">//注掉这些代码是为了去掉左侧反弹效果,上仙们可以去掉试试</span>//if (mIsBeingDragged) {//// Scroll to follow the motion event//final int activePointerIndex = getPointerIndex(ev, mActivePointerId);//if (mActivePointerId == INVALID_POINTER) {//break;//}//final float x = MotionEventCompat.getX(ev, activePointerIndex);//final float deltaX = mLastMotionX - x;//mLastMotionX = x;//float oldScrollX = getScrollX();//float scrollX = oldScrollX + deltaX;//final float leftBound = getLeftBound();//final float rightBound = getRightBound();//if (scrollX < leftBound) {//scrollX = leftBound;//} else if (scrollX > rightBound) {//scrollX = rightBound;//}//// Don't lose the rounded component//mLastMotionX += scrollX - (int) scrollX;//scrollTo((int) scrollX, getScrollY());//pageScrolled((int) scrollX);//}break;case MotionEvent.ACTION_UP:if (mIsBeingDragged) {final VelocityTracker velocityTracker = mVelocityTracker;velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(velocityTracker, mActivePointerId);final int scrollX = getScrollX();//final int widthWithMargin = getWidth();//final float pageOffset = (float) (scrollX % widthWithMargin) / widthWithMargin;// TODO test this. should get better flinging behaviorfinal float pageOffset = (float) (scrollX - getDestScrollX(mCurItem)) / getBehindWidth();final int activePointerIndex = getPointerIndex(ev, mActivePointerId);if (mActivePointerId != INVALID_POINTER) {final float x = MotionEventCompat.getX(ev, activePointerIndex);final int totalDelta = (int) (x - mInitialMotionX);int nextPage = determineTargetPage(pageOffset, initialVelocity, totalDelta);setCurrentItemInternal(nextPage, true, true, initialVelocity);} else {setCurrentItemInternal(mCurItem, true, true, initialVelocity);}mActivePointerId = INVALID_POINTER;endDrag();} else if (mQuickReturn && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {// close the menusetCurrentItem(1);endDrag();}break;case MotionEvent.ACTION_CANCEL:if (mIsBeingDragged) {setCurrentItemInternal(mCurItem, true, true);mActivePointerId = INVALID_POINTER;endDrag();}break;case MotionEventCompat.ACTION_POINTER_DOWN: {final int index = MotionEventCompat.getActionIndex(ev);final float x = MotionEventCompat.getX(ev, index);mLastMotionX = x;mActivePointerId = MotionEventCompat.getPointerId(ev, index);break;}case MotionEventCompat.ACTION_POINTER_UP:onSecondaryPointerUp(ev);int pointerIndex = this.getPointerIndex(ev, mActivePointerId);if (mActivePointerId == INVALID_POINTER)break;mLastMotionX = MotionEventCompat.getX(ev, pointerIndex);break;}return true;}@Overridepublic void scrollTo(int x, int y) {super.scrollTo(x, y);mScrollX = x;if (mEnabled)mViewBehind.scrollBehindTo(mContent, x, y);//((SlidingMenu)getParent()).manageLayers(getPercentOpen());}private int determineTargetPage(float pageOffset, int velocity, int deltaX) {int targetPage = mCurItem;if (Math.abs(deltaX) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) {if (velocity > 0 && deltaX > 0) {targetPage -= 1;} else if (velocity < 0 && deltaX < 0){targetPage += 1;}} else {targetPage = (int) Math.round(mCurItem + pageOffset);}return targetPage;}protected float getPercentOpen() {return Math.abs(mScrollX-mContent.getLeft()) / getBehindWidth();}@Overrideprotected void dispatchDraw(Canvas canvas) {super.dispatchDraw(canvas);// Draw the margin drawable if needed.//mViewBehind.drawShadow(mContent, canvas);//mViewBehind.drawFade(mContent, canvas, getPercentOpen());mViewBehind.drawSelector(mContent, canvas, getPercentOpen());}// variables for drawingprivate float mScrollX = 0.0f;private void onSecondaryPointerUp(MotionEvent ev) {if (DEBUG) Log.v(TAG, "onSecondaryPointerUp called");final int pointerIndex = MotionEventCompat.getActionIndex(ev);final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);if (pointerId == mActivePointerId) {// This was our active pointer going up. Choose a new// active pointer and adjust accordingly.final int newPointerIndex = pointerIndex == 0 ? 1 : 0;mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);if (mVelocityTracker != null) {mVelocityTracker.clear();}}}private void startDrag() {mIsBeingDragged = true;mQuickReturn = false;}private void endDrag() {mQuickReturn = false;mIsBeingDragged = false;mIsUnableToDrag = false;mActivePointerId = INVALID_POINTER;if (mVelocityTracker != null) {mVelocityTracker.recycle();mVelocityTracker = null;}}private void setScrollingCacheEnabled(boolean enabled) {if (mScrollingCacheEnabled != enabled) {mScrollingCacheEnabled = enabled;if (USE_CACHE) {final int size = getChildCount();for (int i = 0; i < size; ++i) {final View child = getChildAt(i);if (child.getVisibility() != GONE) {child.setDrawingCacheEnabled(enabled);}}}}}/** * Tests scrollability within child views of v given a delta of dx. * * @param v View to test for horizontal scrollability * @param checkV Whether the view v passed should itself be checked for scrollability (true), *               or just its children (false). * @param dx Delta scrolled in pixels * @param x X coordinate of the active touch point * @param y Y coordinate of the active touch point * @return true if child views of v can be scrolled by delta of dx. */protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {if (v instanceof ViewGroup) {final ViewGroup group = (ViewGroup) v;final int scrollX = v.getScrollX();final int scrollY = v.getScrollY();final int count = group.getChildCount();// Count backwards - let topmost views consume scroll distance first.for (int i = count - 1; i >= 0; i--) {final View child = group.getChildAt(i);if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&canScroll(child, true, dx, x + scrollX - child.getLeft(),y + scrollY - child.getTop())) {return true;}}}return checkV && ViewCompat.canScrollHorizontally(v, -dx);}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {// Let the focused view and/or our descendants get the key firstreturn super.dispatchKeyEvent(event) || executeKeyEvent(event);}/** * You can call this function yourself to have the scroll view perform * scrolling from a key event, just as if the event had been dispatched to * it by the view hierarchy. * * @param event The key event to execute. * @return Return true if the event was handled, else false. */public boolean executeKeyEvent(KeyEvent event) {boolean handled = false;if (event.getAction() == KeyEvent.ACTION_DOWN) {switch (event.getKeyCode()) {case KeyEvent.KEYCODE_DPAD_LEFT:handled = arrowScroll(FOCUS_LEFT);break;case KeyEvent.KEYCODE_DPAD_RIGHT:handled = arrowScroll(FOCUS_RIGHT);break;case KeyEvent.KEYCODE_TAB:if (Build.VERSION.SDK_INT >= 11) {// The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD// before Android 3.0. Ignore the tab key on those devices.if (KeyEventCompat.hasNoModifiers(event)) {handled = arrowScroll(FOCUS_FORWARD);} else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {handled = arrowScroll(FOCUS_BACKWARD);}}break;}}return handled;}public boolean arrowScroll(int direction) {View currentFocused = findFocus();if (currentFocused == this) currentFocused = null;boolean handled = false;View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,direction);if (nextFocused != null && nextFocused != currentFocused) {if (direction == View.FOCUS_LEFT) {handled = nextFocused.requestFocus();} else if (direction == View.FOCUS_RIGHT) {// If there is nothing to the right, or this is causing us to// jump to the left, then what we really want to do is page right.if (currentFocused != null && nextFocused.getLeft() <= currentFocused.getLeft()) {handled = pageRight();} else {handled = nextFocused.requestFocus();}}} else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {// Trying to move left and nothing there; try to page.handled = pageLeft();} else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {// Trying to move right and nothing there; try to page.handled = pageRight();}if (handled) {playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));}return handled;}boolean pageLeft() {if (mCurItem > 0) {setCurrentItem(mCurItem-1, true);return true;}return false;}boolean pageRight() {if (mCurItem < 1) {setCurrentItem(mCurItem+1, true);return true;}return false;}}

                                        欢迎光临源代码页面.........................

1 0
原创粉丝点击