为了后续对这个项目进行优化,比如透明度动画、背景图的位移动画,以及性能上的优化。

我把这个项目上传到github上面,请大家随时关注。

github地址​ https://github.com/sunguowei


最近项目要做一个QQ5.0的侧滑菜单效果,和传统的侧滑菜单存在着一些差异。想必大家都已经见识过了。

为了不重复发明轮子,先去github上面搜索了一番。

发现了几个类似的,但是还是有一些不同。

下面是搜索到的类似的开源项目。

RESideMenu(ios项目)

​https://github.com/romaonthego/RESideMenu​

仿qq最新侧滑菜单_ide

AndroidResideMenu

​https://github.com/SpecialCyCi/AndroidResideMenu​

仿qq最新侧滑菜单_sed_02

ResideLayout

​https://github.com/kyze8439690/ResideLayout​

仿qq最新侧滑菜单_ide_03


研究了一下这些开源项目的源代码。感觉并不是特别适用于我们自己的项目。所以,我自己又研究了一下。最后的效果如下。当然了,还有很多可以优化的地方,后续再慢慢优化。

仿qq最新侧滑菜单_ide_04

备注:如果图片动画显示不出来,可以点击这个网址查看。

​https://s2.51cto.com/images/blog/202209/07101227_6317fe0ba30b091784.gif​


我是基于SlidingMenu库进行的二次修改,增加了一些转场动画。

大家对这个库应该比较熟悉,下面是SlidingMenu的github地址。非常感谢Jeremy Feinstein提供的这个库,让广大Android Developers省去了非常多的麻烦。

​https://github.com/jfeinstein10/SlidingMenu​

备注:SlidingMenu使用了SherlockActionBar这个库,配置起来会比较麻烦,在文章的最后我会把demo上传,供大家下载,减去了大家自己配置项目的麻烦。

我主要修改了2个类,SlidingMenu.java和CustonViewAbove.java,只是增加了一些功能,并没有修改原本的功能。

做了修改的地方,我做了中文注释,其实实现很简单,几行代码而已。推荐大家下载Demo,然后自己调试一下。Demo的下载地址在文章的末尾。

废话不多说,直接上代码,略微有点长。


[java] ​​ view plain​​ ​​co


  1. public class SlidingMenu extends
  2.   
  3. private static final String TAG = SlidingMenu.class.getSimpleName();  
  4.   
  5. public static final int SLIDING_WINDOW = 0;  
  6. public static final int SLIDING_CONTENT = 1;  
  7. private boolean mActionbarOverlay = false;  
  8.   
  9. /**
  10.      * Constant value for use with setTouchModeAbove(). Allows the SlidingMenu
  11.      * to be opened with a swipe gesture on the screen's margin
  12.      */
  13. public static final int TOUCHMODE_MARGIN = 0;  
  14.   
  15. /**
  16.      * Constant value for use with setTouchModeAbove(). Allows the SlidingMenu
  17.      * to be opened with a swipe gesture anywhere on the screen
  18.      */
  19. public static final int TOUCHMODE_FULLSCREEN = 1;  
  20.   
  21. /**
  22.      * Constant value for use with setTouchModeAbove(). Denies the SlidingMenu
  23.      * to be opened with a swipe gesture
  24.      */
  25. public static final int TOUCHMODE_NONE = 2;  
  26.   
  27. /**
  28.      * Constant value for use with setMode(). Puts the menu to the left of the
  29.      * content.
  30.      */
  31. public static final int LEFT = 0;  
  32.   
  33. /**
  34.      * Constant value for use with setMode(). Puts the menu to the right of the
  35.      * content.
  36.      */
  37. public static final int RIGHT = 1;  
  38.   
  39. /**
  40.      * Constant value for use with setMode(). Puts menus to the left and right
  41.      * of the content.
  42.      */
  43. public static final int LEFT_RIGHT = 2;  
  44.   
  45. private
  46.   
  47. private
  48.   
  49. /** 整体的背景,用一个ImageView代替 */
  50. private
  51.   
  52. private
  53.   
  54. private
  55.   
  56. private
  57.   
  58. /**
  59.      * The listener interface for receiving onOpen events. The class that is
  60.      * interested in processing a onOpen event implements this interface, and
  61.      * the object created with that class is registered with a component using
  62.      * the component's <code>addOnOpenListener<code> method. When
  63.      * the onOpen event occurs, that object's appropriate
  64.      * method is invoked
  65.      */
  66. public interface
  67.   
  68. /**
  69.          * On open.
  70.          */
  71. public void
  72.     }  
  73.   
  74. /**
  75.      * The listener interface for receiving onOpened events. The class that is
  76.      * interested in processing a onOpened event implements this interface, and
  77.      * the object created with that class is registered with a component using
  78.      * the component's <code>addOnOpenedListener<code> method. When
  79.      * the onOpened event occurs, that object's appropriate
  80.      * method is invoked.
  81.      * 
  82.      * @see OnOpenedEvent
  83.      */
  84. public interface
  85.   
  86. /**
  87.          * On opened.
  88.          */
  89. public void
  90.     }  
  91.   
  92. /**
  93.      * The listener interface for receiving onClose events. The class that is
  94.      * interested in processing a onClose event implements this interface, and
  95.      * the object created with that class is registered with a component using
  96.      * the component's <code>addOnCloseListener<code> method. When
  97.      * the onClose event occurs, that object's appropriate
  98.      * method is invoked.
  99.      * 
  100.      * @see OnCloseEvent
  101.      */
  102. public interface
  103.   
  104. /**
  105.          * On close.
  106.          */
  107. public void
  108.     }  
  109.   
  110. /**
  111.      * The listener interface for receiving onClosed events. The class that is
  112.      * interested in processing a onClosed event implements this interface, and
  113.      * the object created with that class is registered with a component using
  114.      * the component's <code>addOnClosedListener<code> method. When
  115.      * the onClosed event occurs, that object's appropriate
  116.      * method is invoked.
  117.      * 
  118.      * @see OnClosedEvent
  119.      */
  120. public interface
  121.   
  122. /**
  123.          * On closed.
  124.          */
  125. public void
  126.     }  
  127.   
  128. /**
  129.      * The Interface CanvasTransformer.
  130.      */
  131. public interface
  132.   
  133. /**
  134.          * Transform canvas.
  135.          * 
  136.          * @param canvas
  137.          *            the canvas
  138.          * @param percentOpen
  139.          *            the percent open
  140.          */
  141. public void transformCanvas(Canvas canvas, float
  142.     }  
  143.   
  144. /**
  145.      * Instantiates a new SlidingMenu.
  146.      * 
  147.      * @param context
  148.      *            the associated Context
  149.      */
  150. public
  151. this(context, null);  
  152.     }  
  153.   
  154. /**
  155.      * Instantiates a new SlidingMenu and attach to Activity.
  156.      * 
  157.      * @param activity
  158.      *            the activity to attach slidingmenu
  159.      * @param slideStyle
  160.      *            the slidingmenu style
  161.      */
  162. public SlidingMenu(Activity activity, int
  163. this(activity, null);  
  164. this.attachToActivity(activity, slideStyle);  
  165.     }  
  166.   
  167. /**
  168.      * Instantiates a new SlidingMenu.
  169.      * 
  170.      * @param context
  171.      *            the associated Context
  172.      * @param attrs
  173.      *            the attrs
  174.      */
  175. public
  176. this(context, attrs, 0);  
  177.     }  
  178.   
  179. /**
  180.      * Instantiates a new SlidingMenu.
  181.      * 
  182.      * @param context
  183.      *            the associated Context
  184.      * @param attrs
  185.      *            the attrs
  186.      * @param defStyle
  187.      *            the def style
  188.      */
  189. public SlidingMenu(Context context, AttributeSet attrs, int
  190. super(context, attrs, defStyle);  
  191. /** SlidingMenu是一个RelativeLayout,这里把背景图ImageView添加到RelativeLayout的最底层。*/
  192. new
  193.                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);  
  194. new
  195.         mViewBackground.setScaleType(ImageView.ScaleType.CENTER_CROP);  
  196.         addView(mViewBackground, backgroundParams);  
  197.           
  198. new
  199.                 LayoutParams.MATCH_PARENT);  
  200. new
  201.         addView(mViewBehind, behindParams);  
  202. new
  203.                 LayoutParams.MATCH_PARENT);  
  204. new
  205.         addView(mViewAbove, aboveParams);  
  206. // register the CustomViewBehind with the CustomViewAbove
  207.         mViewAbove.setCustomViewBehind(mViewBehind);  
  208.         mViewBehind.setCustomViewAbove(mViewAbove);  
  209. new
  210. public static final int POSITION_OPEN = 0;  
  211. public static final int POSITION_CLOSE = 1;  
  212. public static final int POSITION_SECONDARY_OPEN = 2;  
  213.   
  214. public void onPageScrolled(int position, float
  215. int
  216.             }  
  217.   
  218. public void onPageSelected(int
  219. if (position == POSITION_OPEN && mOpenListener != null) {  
  220.                     mOpenListener.onOpen();  
  221. else if (position == POSITION_CLOSE && mCloseListener != null) {  
  222.                     mCloseListener.onClose();  
  223. else if
  224. null) {  
  225.                     mSecondaryOpenListner.onOpen();  
  226.                 }  
  227.             }  
  228.         });  
  229.   
  230. // now style everything!
  231.         TypedArray ta = context.obtainStyledAttributes(attrs,  
  232.                 R.styleable.SlidingMenu);  
  233. // set the above and behind views if defined in xml
  234. int
  235.         setMode(mode);  
  236. int viewAbove = ta.getResourceId(R.styleable.SlidingMenu_viewAbove, -1);  
  237. if (viewAbove != -1) {  
  238.             setContent(viewAbove);  
  239. else
  240. new
  241.         }  
  242. int
  243. 1);  
  244. if (viewBehind != -1) {  
  245.             setMenu(viewBehind);  
  246. else
  247. new
  248.         }  
  249. int
  250.                 TOUCHMODE_MARGIN);  
  251.         setTouchModeAbove(touchModeAbove);  
  252. int
  253.                 R.styleable.SlidingMenu_touchModeBehind, TOUCHMODE_MARGIN);  
  254.         setTouchModeBehind(touchModeBehind);  
  255.   
  256. int offsetBehind = (int) ta.getDimension(  
  257. 1);  
  258. int widthBehind = (int) ta.getDimension(  
  259. 1);  
  260. if (offsetBehind != -1 && widthBehind != -1)  
  261. throw new
  262. "Cannot set both behindOffset and behindWidth for a SlidingMenu");  
  263. else if (offsetBehind != -1)  
  264.             setBehindOffset(offsetBehind);  
  265. else if (widthBehind != -1)  
  266.             setBehindWidth(widthBehind);  
  267. else
  268. 0);  
  269. float
  270. 0.33f);  
  271.         setBehindScrollScale(scrollOffsetBehind);  
  272. int
  273. 1);  
  274. if (shadowRes != -1) {  
  275.             setShadowDrawable(shadowRes);  
  276.         }  
  277. int shadowWidth = (int) ta.getDimension(  
  278. 0);  
  279.         setShadowWidth(shadowWidth);  
  280. boolean
  281. true);  
  282.         setFadeEnabled(fadeEnabled);  
  283. float fadeDeg = ta.getFloat(R.styleable.SlidingMenu_fadeDegree, 0.33f);  
  284.         setFadeDegree(fadeDeg);  
  285. boolean
  286. false);  
  287.         setSelectorEnabled(selectorEnabled);  
  288. int
  289. 1);  
  290. if (selectorRes != -1)  
  291.             setSelectorDrawable(selectorRes);  
  292.         ta.recycle();  
  293.     }  
  294.   
  295. /**
  296.      * Attaches the SlidingMenu to an entire Activity
  297.      * 
  298.      * @param activity
  299.      *            the Activity
  300.      * @param slideStyle
  301.      *            either SLIDING_CONTENT or SLIDING_WINDOW
  302.      */
  303. public void attachToActivity(Activity activity, int
  304. false);  
  305.     }  
  306.   
  307. /**
  308.      * Attaches the SlidingMenu to an entire Activity
  309.      * 
  310.      * @param activity
  311.      *            the Activity
  312.      * @param slideStyle
  313.      *            either SLIDING_CONTENT or SLIDING_WINDOW
  314.      * @param actionbarOverlay
  315.      *            whether or not the ActionBar is overlaid
  316.      */
  317. public void attachToActivity(Activity activity, int
  318. boolean
  319. if
  320. throw new
  321. "slideStyle must be either SLIDING_WINDOW or SLIDING_CONTENT");  
  322.   
  323. if (getParent() != null)  
  324. throw new
  325. "This SlidingMenu appears to already be attached");  
  326.   
  327. // get the window background
  328.         TypedArray a = activity.getTheme().obtainStyledAttributes(  
  329. new int[] { android.R.attr.windowBackground });  
  330. int background = a.getResourceId(0, 0);  
  331.         a.recycle();  
  332.   
  333. switch
  334. case
  335. false;  
  336.             ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();  
  337. 0);  
  338. // save ActionBar themes that have transparent assets
  339.             decorChild.setBackgroundResource(background);  
  340.             decor.removeView(decorChild);  
  341. this);  
  342.             setContent(decorChild);  
  343. break;  
  344. case
  345.             mActionbarOverlay = actionbarOverlay;  
  346. // take the above view out of
  347.             ViewGroup contentParent = (ViewGroup) activity  
  348.                     .findViewById(android.R.id.content);  
  349. 0);  
  350.             contentParent.removeView(content);  
  351. this);  
  352.             setContent(content);  
  353. // save people from having transparent backgrounds
  354. if (content.getBackground() == null)  
  355.                 content.setBackgroundResource(background);  
  356. break;  
  357.         }  
  358.     }  
  359.   
  360. /**
  361.      * Set the above view content from a layout resource. The resource will be
  362.      * inflated, adding all top-level views to the above view.
  363.      * 
  364.      * @param res
  365.      *            the new content
  366.      */
  367. public void setContent(int
  368. null));  
  369.     }  
  370.   
  371. /**
  372.      * Set the above view content to the given View.
  373.      * 
  374.      * @param view
  375.      *            The desired content to display.
  376.      */
  377. public void
  378.         mViewAbove.setContent(view);  
  379.         showContent();  
  380.     }  
  381.   
  382. /**
  383.      * 设置背景图片
  384.      * 
  385.      * @param resid
  386.      */
  387. public void setBackgroundImage(int
  388.         mViewBackground.setBackgroundResource(resid);  
  389.     }  
  390.   
  391. /**
  392.      * Retrieves the current content.
  393.      * 
  394.      * @return the current content
  395.      */
  396. public
  397. return
  398.     }  
  399.   
  400. /**
  401.      * Set the behind view (menu) content from a layout resource. The resource
  402.      * will be inflated, adding all top-level views to the behind view.
  403.      * 
  404.      * @param res
  405.      *            the new content
  406.      */
  407. public void setMenu(int
  408. null));  
  409.     }  
  410.   
  411. /**
  412.      * Set the behind view (menu) content to the given View.
  413.      * 
  414.      * @param view
  415.      *            The desired content to display.
  416.      */
  417. public void
  418.         mViewBehind.setContent(v);  
  419.     }  
  420.   
  421. /**
  422.      * Retrieves the main menu.
  423.      * 
  424.      * @return the main menu
  425.      */
  426. public
  427. return
  428.     }  
  429.   
  430. /**
  431.      * Set the secondary behind view (right menu) content from a layout
  432.      * resource. The resource will be inflated, adding all top-level views to
  433.      * the behind view.
  434.      * 
  435.      * @param res
  436.      *            the new content
  437.      */
  438. public void setSecondaryMenu(int
  439. null));  
  440.     }  
  441.   
  442. /**
  443.      * Set the secondary behind view (right menu) content to the given View.
  444.      * 
  445.      * @param view
  446.      *            The desired content to display.
  447.      */
  448. public void
  449.         mViewBehind.setSecondaryContent(v);  
  450. // mViewBehind.invalidate();
  451.     }  
  452.   
  453. /**
  454.      * Retrieves the current secondary menu (right).
  455.      * 
  456.      * @return the current menu
  457.      */
  458. public
  459. return
  460.     }  
  461.   
  462. /**
  463.      * Sets the sliding enabled.
  464.      * 
  465.      * @param b
  466.      *            true to enable sliding, false to disable it.
  467.      */
  468. public void setSlidingEnabled(boolean
  469.         mViewAbove.setSlidingEnabled(b);  
  470.     }  
  471.   
  472. /**
  473.      * Checks if is sliding enabled.
  474.      * 
  475.      * @return true, if is sliding enabled
  476.      */
  477. public boolean
  478. return
  479.     }  
  480.   
  481. /**
  482.      * Sets which side the SlidingMenu should appear on.
  483.      * 
  484.      * @param mode
  485.      *            must be either SlidingMenu.LEFT or SlidingMenu.RIGHT
  486.      */
  487. public void setMode(int
  488. if
  489. throw new
  490. "SlidingMenu mode must be LEFT, RIGHT, or LEFT_RIGHT");  
  491.         }  
  492.         mViewBehind.setMode(mode);  
  493.     }  
  494.   
  495. /**
  496.      * Returns the current side that the SlidingMenu is on.
  497.      * 
  498.      * @return the current mode, either SlidingMenu.LEFT or SlidingMenu.RIGHT
  499.      */
  500. public int
  501. return
  502.     }  
  503.   
  504. /**
  505.      * Sets whether or not the SlidingMenu is in static mode (i.e. nothing is
  506.      * moving and everything is showing)
  507.      * 
  508.      * @param b
  509.      *            true to set static mode, false to disable static mode.
  510.      */
  511. public void setStatic(boolean
  512. if
  513. false);  
  514. null);  
  515. 1);  
  516. // mViewBehind.setCurrentItem(0);
  517. else
  518. 1);  
  519. // mViewBehind.setCurrentItem(1);
  520.             mViewAbove.setCustomViewBehind(mViewBehind);  
  521. true);  
  522.         }  
  523.     }  
  524.   
  525. /**
  526.      * Opens the menu and shows the menu view.
  527.      */
  528. public void
  529. true);  
  530.     }  
  531.   
  532. /**
  533.      * Opens the menu and shows the menu view.
  534.      * 
  535.      * @param animate
  536.      *            true to animate the transition, false to ignore animation
  537.      */
  538. public void showMenu(boolean
  539. 0, animate);  
  540.     }  
  541.   
  542. /**
  543.      * Opens the menu and shows the secondary menu view. Will default to the
  544.      * regular menu if there is only one.
  545.      */
  546. public void
  547. true);  
  548.     }  
  549.   
  550. /**
  551.      * Opens the menu and shows the secondary (right) menu view. Will default to
  552.      * the regular menu if there is only one.
  553.      * 
  554.      * @param animate
  555.      *            true to animate the transition, false to ignore animation
  556.      */
  557. public void showSecondaryMenu(boolean
  558. 2, animate);  
  559.     }  
  560.   
  561. /**
  562.      * Closes the menu and shows the above view.
  563.      */
  564. public void
  565. true);  
  566.     }  
  567.   
  568. /**
  569.      * Closes the menu and shows the above view.
  570.      * 
  571.      * @param animate
  572.      *            true to animate the transition, false to ignore animation
  573.      */
  574. public void showContent(boolean
  575. 1, animate);  
  576.     }  
  577.   
  578. /**
  579.      * Toggle the SlidingMenu. If it is open, it will be closed, and vice versa.
  580.      */
  581. public void
  582. true);  
  583.     }  
  584.   
  585. /**
  586.      * Toggle the SlidingMenu. If it is open, it will be closed, and vice versa.
  587.      * 
  588.      * @param animate
  589.      *            true to animate the transition, false to ignore animation
  590.      */
  591. public void toggle(boolean
  592. if
  593.             showContent(animate);  
  594. else
  595.             showMenu(animate);  
  596.         }  
  597.     }  
  598.   
  599. /**
  600.      * Checks if is the behind view showing.
  601.      * 
  602.      * @return Whether or not the behind view is showing
  603.      */
  604. public boolean
  605. return mViewAbove.getCurrentItem() == 0
  606. 2;  
  607.     }  
  608.   
  609. /**
  610.      * Checks if is the behind view showing.
  611.      * 
  612.      * @return Whether or not the behind view is showing
  613.      */
  614. public boolean
  615. return mViewAbove.getCurrentItem() == 2;  
  616.     }  
  617.   
  618. /**
  619.      * Gets the behind offset.
  620.      * 
  621.      * @return The margin on the right of the screen that the behind view
  622.      *         scrolls to
  623.      */
  624. public int
  625. return
  626.     }  
  627.   
  628. /**
  629.      * Sets the behind offset.
  630.      * 
  631.      * @param i
  632.      *            The margin, in pixels, on the right of the screen that the
  633.      *            behind view scrolls to.
  634.      */
  635. public void setBehindOffset(int
  636. // RelativeLayout.LayoutParams params =
  637. // ((RelativeLayout.LayoutParams)mViewBehind.getLayoutParams());
  638. // int bottom = params.bottomMargin;
  639. // int top = params.topMargin;
  640. // int left = params.leftMargin;
  641. // params.setMargins(left, top, i, bottom);
  642.         mViewBehind.setWidthOffset(i);  
  643.     }  
  644.   
  645. /**
  646.      * Sets the behind offset.
  647.      * 
  648.      * @param resID
  649.      *            The dimension resource id to be set as the behind offset. The
  650.      *            menu, when open, will leave this width margin on the right of
  651.      *            the screen.
  652.      */
  653. public void setBehindOffsetRes(int
  654. int i = (int) getContext().getResources().getDimension(resID);  
  655.         setBehindOffset(i);  
  656.     }  
  657.   
  658. /**
  659.      * Sets the above offset.
  660.      * 
  661.      * @param i
  662.      *            the new above offset, in pixels
  663.      */
  664. public void setAboveOffset(int
  665.         mViewAbove.setAboveOffset(i);  
  666.     }  
  667.   
  668. /**
  669.      * Sets the above offset.
  670.      * 
  671.      * @param resID
  672.      *            The dimension resource id to be set as the above offset.
  673.      */
  674. public void setAboveOffsetRes(int
  675. int i = (int) getContext().getResources().getDimension(resID);  
  676.         setAboveOffset(i);  
  677.     }  
  678.   
  679. /**
  680.      * Sets the behind width.
  681.      * 
  682.      * @param i
  683.      *            The width the Sliding Menu will open to, in pixels
  684.      */
  685. @SuppressWarnings("deprecation")  
  686. public void setBehindWidth(int
  687. int
  688.         Display display = ((WindowManager) getContext().getSystemService(  
  689.                 Context.WINDOW_SERVICE)).getDefaultDisplay();  
  690. try
  691. class;  
  692. class
  693. new
  694. "getSize", parameterTypes);  
  695.             method.invoke(display, parameter);  
  696.             width = parameter.x;  
  697. catch
  698.             width = display.getWidth();  
  699.         }  
  700.         setBehindOffset(width - i);  
  701.     }  
  702.   
  703. /**
  704.      * Sets the behind width.
  705.      * 
  706.      * @param res
  707.      *            The dimension resource id to be set as the behind width
  708.      *            offset. The menu, when open, will open this wide.
  709.      */
  710. public void setBehindWidthRes(int
  711. int i = (int) getContext().getResources().getDimension(res);  
  712.         setBehindWidth(i);  
  713.     }  
  714.   
  715. /**
  716.      * Gets the behind scroll scale.
  717.      * 
  718.      * @return The scale of the parallax scroll
  719.      */
  720. public float
  721. return
  722.     }  
  723.   
  724. /**
  725.      * Gets the touch mode margin threshold
  726.      * 
  727.      * @return the touch mode margin threshold
  728.      */
  729. public int
  730. return
  731.     }  
  732.   
  733. /**
  734.      * Set the touch mode margin threshold
  735.      * 
  736.      * @param touchmodeMarginThreshold
  737.      */
  738. public void setTouchmodeMarginThreshold(int
  739.         mViewBehind.setMarginThreshold(touchmodeMarginThreshold);  
  740.     }  
  741.   
  742. /**
  743.      * Sets the behind scroll scale.
  744.      * 
  745.      * @param f
  746.      *            The scale of the parallax scroll (i.e. 1.0f scrolls 1 pixel
  747.      *            for every 1 pixel that the above view scrolls and 0.0f scrolls
  748.      *            0 pixels)
  749.      */
  750. public void setBehindScrollScale(float
  751. if (f < 0 && f > 1)  
  752. throw new
  753. "ScrollScale must be between 0 and 1");  
  754.         mViewBehind.setScrollScale(f);  
  755.     }  
  756.   
  757. /**
  758.      * Sets the behind canvas transformer.
  759.      * 
  760.      * @param t
  761.      *            the new behind canvas transformer
  762.      */
  763. public void
  764.         mViewBehind.setCanvasTransformer(t);  
  765.     }  
  766.   
  767. /**
  768.      * 设置右侧视图的转场动画
  769.      * 
  770.      * @param t
  771.      *            the new above canvas transformer
  772.      */
  773. public void
  774.         mViewAbove.setCanvasTransformer(t);  
  775.     }  
  776.   
  777. /**
  778.      * Gets the touch mode above.
  779.      * 
  780.      * @return the touch mode above
  781.      */
  782. public int
  783. return
  784.     }  
  785.   
  786. /**
  787.      * Controls whether the SlidingMenu can be opened with a swipe gesture.
  788.      * Options are {@link #TOUCHMODE_MARGIN TOUCHMODE_MARGIN},
  789.      * {@link #TOUCHMODE_FULLSCREEN TOUCHMODE_FULLSCREEN}, or
  790.      * {@link #TOUCHMODE_NONE TOUCHMODE_NONE}
  791.      * 
  792.      * @param i
  793.      *            the new touch mode
  794.      */
  795. public void setTouchModeAbove(int
  796. if
  797.                 && i != TOUCHMODE_NONE) {  
  798. throw new
  799. "TouchMode must be set to either"
  800. "TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN or TOUCHMODE_NONE.");  
  801.         }  
  802.         mViewAbove.setTouchMode(i);  
  803.     }  
  804.   
  805. /**
  806.      * Controls whether the SlidingMenu can be opened with a swipe gesture.
  807.      * Options are {@link #TOUCHMODE_MARGIN TOUCHMODE_MARGIN},
  808.      * {@link #TOUCHMODE_FULLSCREEN TOUCHMODE_FULLSCREEN}, or
  809.      * {@link #TOUCHMODE_NONE TOUCHMODE_NONE}
  810.      * 
  811.      * @param i
  812.      *            the new touch mode
  813.      */
  814. public void setTouchModeBehind(int
  815. if
  816.                 && i != TOUCHMODE_NONE) {  
  817. throw new
  818. "TouchMode must be set to either"
  819. "TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN or TOUCHMODE_NONE.");  
  820.         }  
  821.         mViewBehind.setTouchMode(i);  
  822.     }  
  823.   
  824. /**
  825.      * Sets the shadow drawable.
  826.      * 
  827.      * @param resId
  828.      *            the resource ID of the new shadow drawable
  829.      */
  830. public void setShadowDrawable(int
  831.         setShadowDrawable(getContext().getResources().getDrawable(resId));  
  832.     }  
  833.   
  834. /**
  835.      * Sets the shadow drawable.
  836.      * 
  837.      * @param d
  838.      *            the new shadow drawable
  839.      */
  840. public void
  841.         mViewBehind.setShadowDrawable(d);  
  842.     }  
  843.   
  844. /**
  845.      * Sets the secondary (right) shadow drawable.
  846.      * 
  847.      * @param resId
  848.      *            the resource ID of the new shadow drawable
  849.      */
  850. public void setSecondaryShadowDrawable(int
  851.         setSecondaryShadowDrawable(getContext().getResources().getDrawable(  
  852.                 resId));  
  853.     }  
  854.   
  855. /**
  856.      * Sets the secondary (right) shadow drawable.
  857.      * 
  858.      * @param d
  859.      *            the new shadow drawable
  860.      */
  861. public void
  862.         mViewBehind.setSecondaryShadowDrawable(d);  
  863.     }  
  864.   
  865. /**
  866.      * Sets the shadow width.
  867.      * 
  868.      * @param resId
  869.      *            The dimension resource id to be set as the shadow width.
  870.      */
  871. public void setShadowWidthRes(int
  872. int) getResources().getDimension(resId));  
  873.     }  
  874.   
  875. /**
  876.      * Sets the shadow width.
  877.      * 
  878.      * @param pixels
  879.      *            the new shadow width, in pixels
  880.      */
  881. public void setShadowWidth(int
  882.         mViewBehind.setShadowWidth(pixels);  
  883.     }  
  884.   
  885. /**
  886.      * Enables or disables the SlidingMenu's fade in and out
  887.      * 
  888.      * @param b
  889.      *            true to enable fade, false to disable it
  890.      */
  891. public void setFadeEnabled(boolean
  892.         mViewBehind.setFadeEnabled(b);  
  893.     }  
  894.   
  895. /**
  896.      * Sets how much the SlidingMenu fades in and out. Fade must be enabled, see
  897.      * {@link #setFadeEnabled(boolean) setFadeEnabled(boolean)}
  898.      * 
  899.      * @param f
  900.      *            the new fade degree, between 0.0f and 1.0f
  901.      */
  902. public void setFadeDegree(float
  903.         mViewBehind.setFadeDegree(f);  
  904.     }  
  905.   
  906. /**
  907.      * Enables or disables whether the selector is drawn
  908.      * 
  909.      * @param b
  910.      *            true to draw the selector, false to not draw the selector
  911.      */
  912. public void setSelectorEnabled(boolean
  913. true);  
  914.     }  
  915.   
  916. /**
  917.      * Sets the selected view. The selector will be drawn here
  918.      * 
  919.      * @param v
  920.      *            the new selected view
  921.      */
  922. public void
  923.         mViewBehind.setSelectedView(v);  
  924.     }  
  925.   
  926. /**
  927.      * Sets the selector drawable.
  928.      * 
  929.      * @param res
  930.      *            a resource ID for the selector drawable
  931.      */
  932. public void setSelectorDrawable(int
  933.         mViewBehind.setSelectorBitmap(BitmapFactory.decodeResource(  
  934.                 getResources(), res));  
  935.     }  
  936.   
  937. /**
  938.      * Sets the selector drawable.
  939.      * 
  940.      * @param b
  941.      *            the new selector bitmap
  942.      */
  943. public void
  944.         mViewBehind.setSelectorBitmap(b);  
  945.     }  
  946.   
  947. /**
  948.      * Add a View ignored by the Touch Down event when mode is Fullscreen
  949.      * 
  950.      * @param v
  951.      *            a view to be ignored
  952.      */
  953. public void
  954.         mViewAbove.addIgnoredView(v);  
  955.     }  
  956.   
  957. /**
  958.      * Remove a View ignored by the Touch Down event when mode is Fullscreen
  959.      * 
  960.      * @param v
  961.      *            a view not wanted to be ignored anymore
  962.      */
  963. public void
  964.         mViewAbove.removeIgnoredView(v);  
  965.     }  
  966.   
  967. /**
  968.      * Clear the list of Views ignored by the Touch Down event when mode is
  969.      * Fullscreen
  970.      */
  971. public void
  972.         mViewAbove.clearIgnoredViews();  
  973.     }  
  974.   
  975. /**
  976.      * Sets the OnOpenListener. {@link OnOpenListener#onOpen()
  977.      * OnOpenListener.onOpen()} will be called when the SlidingMenu is opened
  978.      * 
  979.      * @param listener
  980.      *            the new OnOpenListener
  981.      */
  982. public void
  983. // mViewAbove.setOnOpenListener(listener);
  984.         mOpenListener = listener;  
  985.     }  
  986.   
  987. /**
  988.      * Sets the OnOpenListner for secondary menu {@link OnOpenListener#onOpen()
  989.      * OnOpenListener.onOpen()} will be called when the secondary SlidingMenu is
  990.      * opened
  991.      * 
  992.      * @param listener
  993.      *            the new OnOpenListener
  994.      */
  995.   
  996. public void
  997.         mSecondaryOpenListner = listener;  
  998.     }  
  999.   
  1000. /**
  1001.      * Sets the OnCloseListener. {@link OnCloseListener#onClose()
  1002.      * OnCloseListener.onClose()} will be called when any one of the SlidingMenu
  1003.      * is closed
  1004.      * 
  1005.      * @param listener
  1006.      *            the new setOnCloseListener
  1007.      */
  1008. public void
  1009. // mViewAbove.setOnCloseListener(listener);
  1010.         mCloseListener = listener;  
  1011.     }  
  1012.   
  1013. /**
  1014.      * Sets the OnOpenedListener. {@link OnOpenedListener#onOpened()
  1015.      * OnOpenedListener.onOpened()} will be called after the SlidingMenu is
  1016.      * opened
  1017.      * 
  1018.      * @param listener
  1019.      *            the new OnOpenedListener
  1020.      */
  1021. public void
  1022.         mViewAbove.setOnOpenedListener(listener);  
  1023.     }  
  1024.   
  1025. /**
  1026.      * Sets the OnClosedListener. {@link OnClosedListener#onClosed()
  1027.      * OnClosedListener.onClosed()} will be called after the SlidingMenu is
  1028.      * closed
  1029.      * 
  1030.      * @param listener
  1031.      *            the new OnClosedListener
  1032.      */
  1033. public void
  1034.         mViewAbove.setOnClosedListener(listener);  
  1035.     }  
  1036.   
  1037. public static class SavedState extends
  1038.   
  1039. private final int
  1040.   
  1041. public SavedState(Parcelable superState, int
  1042. super(superState);  
  1043.             mItem = item;  
  1044.         }  
  1045.   
  1046. private
  1047. super(in);  
  1048.             mItem = in.readInt();  
  1049.         }  
  1050.   
  1051. public int
  1052. return
  1053.         }  
  1054.   
  1055. /*
  1056.          * (non-Javadoc)
  1057.          * 
  1058.          * @see android.view.AbsSavedState#writeToParcel(android.os.Parcel, int)
  1059.          */
  1060. public void writeToParcel(Parcel out, int
  1061. super.writeToParcel(out, flags);  
  1062.             out.writeInt(mItem);  
  1063.         }  
  1064.   
  1065. public static final Parcelable.Creator<SavedState> CREATOR = new
  1066. public
  1067. return new
  1068.             }  
  1069.   
  1070. public SavedState[] newArray(int
  1071. return new
  1072.             }  
  1073.         };  
  1074.   
  1075.     }  
  1076.   
  1077. /*
  1078.      * (non-Javadoc)
  1079.      * 
  1080.      * @see android.view.View#onSaveInstanceState()
  1081.      */
  1082. @Override
  1083. protected
  1084. super.onSaveInstanceState();  
  1085. new
  1086. return
  1087.     }  
  1088.   
  1089. /*
  1090.      * (non-Javadoc)
  1091.      * 
  1092.      * @see android.view.View#onRestoreInstanceState(android.os.Parcelable)
  1093.      */
  1094. @Override
  1095. protected void
  1096.         SavedState ss = (SavedState) state;  
  1097. super.onRestoreInstanceState(ss.getSuperState());  
  1098.         mViewAbove.setCurrentItem(ss.getItem());  
  1099.     }  
  1100.   
  1101. /*
  1102.      * (non-Javadoc)
  1103.      * 
  1104.      * @see android.view.ViewGroup#fitSystemWindows(android.graphics.Rect)
  1105.      */
  1106. @SuppressLint("NewApi")  
  1107. @Override
  1108. protected boolean
  1109. int
  1110. int
  1111. int
  1112. int
  1113. if
  1114. "setting padding!");  
  1115.             setPadding(leftPadding, topPadding, rightPadding, bottomPadding);  
  1116.         }  
  1117. return true;  
  1118.     }  
  1119.   
  1120. @TargetApi(Build.VERSION_CODES.HONEYCOMB)  
  1121. public void manageLayers(float
  1122. if (Build.VERSION.SDK_INT < 11)  
  1123. return;  
  1124.   
  1125. boolean layer = percentOpen > 0.0f && percentOpen < 1.0f;  
  1126. final int
  1127.                 : View.LAYER_TYPE_NONE;  
  1128.   
  1129. if
  1130. new
  1131. public void
  1132. "changing layerType. hardware? "
  1133.                             + (layerType == View.LAYER_TYPE_HARDWARE));  
  1134. null);  
  1135. null);  
  1136. if (getSecondaryMenu() != null) {  
  1137. null);  
  1138.                     }  
  1139.                 }  
  1140.             });  
  1141.         }  
  1142.     }  
  1143.   
  1144. }  


[java] ​​ view plain​​ ​​cop


  1. public class CustomViewAbove extends
  2.   
  3. private static final String TAG = "CustomViewAbove";  
  4. private static final boolean DEBUG = false;  
  5.   
  6. private static final boolean USE_CACHE = false;  
  7.   
  8. private static final int MAX_SETTLE_DURATION = 600; // ms
  9. private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
  10.   
  11. private static final Interpolator sInterpolator = new
  12. public float getInterpolation(float
  13. 1.0f;  
  14. return t * t * t * t * t + 1.0f;  
  15.         }  
  16.     };  
  17.   
  18. private
  19.   
  20. private int
  21. private
  22.   
  23. private boolean
  24.   
  25. private boolean
  26.   
  27. private boolean
  28. private boolean
  29. private int
  30. private float
  31. /**
  32.      * Position of the last motion event.
  33.      */
  34. private float
  35. private float
  36. /**
  37.      * ID of the active pointer. This is used to retain consistency during
  38.      * drags/flings if multiple pointers are used.
  39.      */
  40. protected int
  41. /**
  42.      * Sentinel value for no current active pointer.
  43.      * Used by {@link #mActivePointerId}.
  44.      */
  45. private static final int INVALID_POINTER = -1;  
  46. /** 保存转场动画的变量*/
  47. private
  48.       
  49. /**
  50.      * Determines speed during touch scrolling
  51.      */
  52. protected
  53. private int
  54. protected int
  55. private int
  56.   
  57. private
  58. //  private int mMode;
  59. private boolean mEnabled = true;  
  60.   
  61. private
  62. private
  63.   
  64. //  private OnCloseListener mCloseListener;
  65. //  private OnOpenListener mOpenListener;
  66. private
  67. private
  68.   
  69. private List<View> mIgnoredViews = new
  70.   
  71. //  private int mScrollState = SCROLL_STATE_IDLE;
  72.   
  73. /**
  74.      * Callback interface for responding to changing state of the selected page.
  75.      */
  76. public interface
  77.   
  78. /**
  79.          * This method will be invoked when the current page is scrolled, either as part
  80.          * of a programmatically initiated smooth scroll or a user initiated touch scroll.
  81.          *
  82.          * @param position Position index of the first page currently being displayed.
  83.          *                 Page position+1 will be visible if positionOffset is nonzero.
  84.          * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
  85.          * @param positionOffsetPixels Value in pixels indicating the offset from position.
  86.          */
  87. public void onPageScrolled(int position, float positionOffset, int
  88.   
  89. /**
  90.          * This method will be invoked when a new page becomes selected. Animation is not
  91.          * necessarily complete.
  92.          *
  93.          * @param position Position index of the new selected page.
  94.          */
  95. public void onPageSelected(int
  96.   
  97.     }  
  98.   
  99. /**
  100.      * Simple implementation of the {@link OnPageChangeListener} interface with stub
  101.      * implementations of each method. Extend this if you do not intend to override
  102.      * every method of {@link OnPageChangeListener}.
  103.      */
  104. public static class SimpleOnPageChangeListener implements
  105.   
  106. public void onPageScrolled(int position, float positionOffset, int
  107. // This space for rent
  108.         }  
  109.   
  110. public void onPageSelected(int
  111. // This space for rent
  112.         }  
  113.   
  114. public void onPageScrollStateChanged(int
  115. // This space for rent
  116.         }  
  117.   
  118.     }  
  119.   
  120. public
  121. this(context, null);  
  122.     }  
  123.   
  124. public
  125. super(context, attrs);  
  126.         initCustomViewAbove();  
  127.     }  
  128.   
  129. void
  130. false);  
  131.         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);  
  132. true);  
  133. final
  134. new
  135. final
  136.         mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);  
  137.         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();  
  138.         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();  
  139. new
  140. public void onPageSelected(int
  141. if (mViewBehind != null) {  
  142. switch
  143. case 0:  
  144. case 2:  
  145. true);  
  146. break;  
  147. case 1:  
  148. false);  
  149. break;  
  150.                     }  
  151.                 }  
  152.             }  
  153.         });  
  154.   
  155. final float
  156. int) (MIN_DISTANCE_FOR_FLING * density);  
  157.     }  
  158.   
  159. /**
  160.      * Set the currently selected page. If the CustomViewPager has already been through its first
  161.      * layout there will be a smooth animated transition between the current item and the
  162.      * specified item.
  163.      *
  164.      * @param item Item index to select
  165.      */
  166. public void setCurrentItem(int
  167. true, false);  
  168.     }  
  169.   
  170. /**
  171.      * Set the currently selected page.
  172.      *
  173.      * @param item Item index to select
  174.      * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately
  175.      */
  176. public void setCurrentItem(int item, boolean
  177. false);  
  178.     }  
  179.   
  180. public int
  181. return
  182.     }  
  183.   
  184. void setCurrentItemInternal(int item, boolean smoothScroll, boolean
  185. 0);  
  186.     }  
  187.   
  188. void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int
  189. if
  190. false);  
  191. return;  
  192.         }  
  193.   
  194.         item = mViewBehind.getMenuPage(item);  
  195.   
  196. final boolean
  197.         mCurItem = item;  
  198. final int
  199. if (dispatchSelected && mOnPageChangeListener != null) {  
  200.             mOnPageChangeListener.onPageSelected(item);  
  201.         }  
  202. if (dispatchSelected && mInternalPageChangeListener != null) {  
  203.             mInternalPageChangeListener.onPageSelected(item);  
  204.         }  
  205. if
  206. 0, velocity);  
  207. else
  208.             completeScroll();  
  209. 0);  
  210.         }  
  211.     }  
  212.   
  213. /**
  214.      * Set a listener that will be invoked whenever the page changes or is incrementally
  215.      * scrolled. See {@link OnPageChangeListener}.
  216.      *
  217.      * @param listener Listener to set
  218.      */
  219. public void
  220.         mOnPageChangeListener = listener;  
  221.     }  
  222. /*
  223.     public void setOnOpenListener(OnOpenListener l) {
  224.         mOpenListener = l;
  225.     }

  226.     public void setOnCloseListener(OnCloseListener l) {
  227.         mCloseListener = l;
  228.     }
  229.      */
  230. public void
  231.         mOpenedListener = l;  
  232.     }  
  233.   
  234. public void
  235.         mClosedListener = l;  
  236.     }  
  237.   
  238. /**
  239.      * Set a separate OnPageChangeListener for internal use by the support library.
  240.      *
  241.      * @param listener Listener to set
  242.      * @return The old listener that was set, if any.
  243.      */
  244.     OnPageChangeListener setInternalPageChangeListener(OnPageChangeListener listener) {  
  245.         OnPageChangeListener oldListener = mInternalPageChangeListener;  
  246.         mInternalPageChangeListener = listener;  
  247. return
  248.     }  
  249.   
  250. public void
  251. if
  252.             mIgnoredViews.add(v);  
  253.         }  
  254.     }  
  255.   
  256. public void
  257.         mIgnoredViews.remove(v);  
  258.     }  
  259.   
  260. public void
  261.         mIgnoredViews.clear();  
  262.     }  
  263.   
  264. // We want the duration of the page snap animation to be influenced by the distance that
  265. // the screen has to travel, however, we don't want this duration to be effected in a
  266. // purely linear fashion. Instead, we use this method to moderate the effect that the distance
  267. // of travel has on the overall snap duration.
  268. float distanceInfluenceForSnapDuration(float
  269. 0.5f; // center the values about 0.
  270. 0.3f * Math.PI / 2.0f;  
  271. return (float) FloatMath.sin(f);  
  272.     }  
  273.   
  274. public int getDestScrollX(int
  275. switch
  276. case 0:  
  277. case 2:  
  278. return
  279. case 1:  
  280. return
  281.         }  
  282. return 0;  
  283.     }  
  284.   
  285. private int
  286. return
  287.     }  
  288.   
  289. private int
  290. return
  291.     }  
  292.   
  293. public int
  294. return
  295.     }  
  296.   
  297. public boolean
  298. return mCurItem == 0 || mCurItem == 2;  
  299.     }  
  300.   
  301. private boolean
  302. new
  303. for
  304.             v.getHitRect(rect);  
  305. if (rect.contains((int)ev.getX(), (int)ev.getY())) return true;  
  306.         }  
  307. return false;  
  308.     }  
  309.   
  310. public int
  311. if (mViewBehind == null) {  
  312. return 0;  
  313. else
  314. return
  315.         }  
  316.     }  
  317.   
  318. public int getChildWidth(int
  319. switch
  320. case 0:  
  321. return
  322. case 1:  
  323. return
  324. default:  
  325. return 0;  
  326.         }  
  327.     }  
  328.   
  329. public boolean
  330. return
  331.     }  
  332.   
  333. public void setSlidingEnabled(boolean
  334.         mEnabled = b;  
  335.     }  
  336.   
  337. /**
  338.      * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
  339.      *
  340.      * @param x the number of pixels to scroll by on the X axis
  341.      * @param y the number of pixels to scroll by on the Y axis
  342.      */
  343. void smoothScrollTo(int x, int
  344. 0);  
  345.     }  
  346.   
  347. /**
  348.      * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
  349.      *
  350.      * @param x the number of pixels to scroll by on the X axis
  351.      * @param y the number of pixels to scroll by on the Y axis
  352.      * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)
  353.      */
  354. void smoothScrollTo(int x, int y, int
  355. if (getChildCount() == 0) {  
  356. // Nothing to do.
  357. false);  
  358. return;  
  359.         }  
  360. int
  361. int
  362. int
  363. int
  364. if (dx == 0 && dy == 0) {  
  365.             completeScroll();  
  366. if
  367. if (mOpenedListener != null)  
  368.                     mOpenedListener.onOpened();  
  369. else
  370. if (mClosedListener != null)  
  371.                     mClosedListener.onClosed();  
  372.             }  
  373. return;  
  374.         }  
  375.   
  376. true);  
  377. true;  
  378.   
  379. final int
  380. final int halfWidth = width / 2;  
  381. final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);  
  382. final float
  383.                 distanceInfluenceForSnapDuration(distanceRatio);  
  384.   
  385. int duration = 0;  
  386.         velocity = Math.abs(velocity);  
  387. if (velocity > 0) {  
  388. 4 * Math.round(1000
  389. else
  390. final float pageDelta = (float) Math.abs(dx) / width;  
  391. int) ((pageDelta + 1) * 100);  
  392.             duration = MAX_SETTLE_DURATION;  
  393.         }  
  394.         duration = Math.min(duration, MAX_SETTLE_DURATION);  
  395.   
  396.         mScroller.startScroll(sx, sy, dx, dy, duration);  
  397.         invalidate();  
  398.     }  
  399.   
  400. public void
  401. if (mContent != null)   
  402. this.removeView(mContent);  
  403.         mContent = v;  
  404.         addView(mContent);  
  405.     }  
  406.   
  407. public
  408. return
  409.     }  
  410.   
  411. public void
  412.         mViewBehind = cvb;  
  413.     }  
  414.   
  415. @Override
  416. protected void onMeasure(int widthMeasureSpec, int
  417.   
  418. int width = getDefaultSize(0, widthMeasureSpec);  
  419. int height = getDefaultSize(0, heightMeasureSpec);  
  420.         setMeasuredDimension(width, height);  
  421.   
  422. final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);  
  423. final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);  
  424.         mContent.measure(contentWidth, contentHeight);  
  425.     }  
  426.   
  427. @Override
  428. protected void onSizeChanged(int w, int h, int oldw, int
  429. super.onSizeChanged(w, h, oldw, oldh);  
  430. // Make sure scroll position is set correctly.
  431. if
  432. // [ChrisJ] - This fixes the onConfiguration change for orientation issue..
  433. // maybe worth having a look why the recomputeScroll pos is screwing
  434. // up?
  435.             completeScroll();  
  436.             scrollTo(getDestScrollX(mCurItem), getScrollY());  
  437.         }  
  438.     }  
  439.   
  440. @Override
  441. protected void onLayout(boolean changed, int l, int t, int r, int
  442. final int
  443. final int
  444. 0, 0, width, height);  
  445.     }  
  446.   
  447. public void setAboveOffset(int
  448. //      RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams)mContent.getLayoutParams());
  449. //      params.setMargins(i, params.topMargin, params.rightMargin, params.bottomMargin);
  450.         mContent.setPadding(i, mContent.getPaddingTop(),   
  451.                 mContent.getPaddingRight(), mContent.getPaddingBottom());  
  452.     }  
  453.   
  454.   
  455. @Override
  456. public void
  457. if
  458. if
  459. int
  460. int
  461. int
  462. int
  463.   
  464. if
  465.                     scrollTo(x, y);  
  466.                     pageScrolled(x);  
  467.                 }  
  468.   
  469. // Keep on drawing until the animation has finished.
  470.                 invalidate();  
  471. return;  
  472.             }  
  473.         }  
  474.   
  475. // Done with scroll, clean up state.
  476.         completeScroll();  
  477.     }  
  478.   
  479. private void pageScrolled(int
  480. final int
  481. final int
  482. final int
  483. final float offset = (float) offsetPixels / widthWithMargin;  
  484.   
  485.         onPageScrolled(position, offset, offsetPixels);  
  486.     }  
  487.   
  488. /**
  489.      * This method will be invoked when the current page is scrolled, either as part
  490.      * of a programmatically initiated smooth scroll or a user initiated touch scroll.
  491.      * If you override this method you must call through to the superclass implementation
  492.      * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled
  493.      * returns.
  494.      *
  495.      * @param position Position index of the first page currently being displayed.
  496.      *                 Page position+1 will be visible if positionOffset is nonzero.
  497.      * @param offset Value from [0, 1) indicating the offset from the page at position.
  498.      * @param offsetPixels Value in pixels indicating the offset from position.
  499.      */
  500. protected void onPageScrolled(int position, float offset, int
  501. if (mOnPageChangeListener != null) {  
  502.             mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);  
  503.         }  
  504. if (mInternalPageChangeListener != null) {  
  505.             mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels);  
  506.         }  
  507.     }  
  508.   
  509. private void
  510. boolean
  511. if
  512. // Done with scroll, no longer want to cache view drawing.
  513. false);  
  514.             mScroller.abortAnimation();  
  515. int
  516. int
  517. int
  518. int
  519. if
  520.                 scrollTo(x, y);  
  521.             }  
  522. if
  523. if (mOpenedListener != null)  
  524.                     mOpenedListener.onOpened();  
  525. else
  526. if (mClosedListener != null)  
  527.                     mClosedListener.onClosed();  
  528.             }  
  529.         }  
  530. false;  
  531.     }  
  532.   
  533. protected int
  534.   
  535. public void setTouchMode(int
  536.         mTouchMode = i;  
  537.     }  
  538.   
  539. public int
  540. return
  541.     }  
  542.   
  543. private boolean
  544. int x = (int) (ev.getX() + mScrollX);  
  545. if
  546. return
  547. else
  548. switch
  549. case
  550. return
  551. case
  552. return false;  
  553. case
  554. return
  555.             }  
  556.         }  
  557. return false;  
  558.     }  
  559.   
  560. private boolean thisSlideAllowed(float
  561. boolean allowed = false;  
  562. if
  563.             allowed = mViewBehind.menuOpenSlideAllowed(dx);  
  564. else
  565.             allowed = mViewBehind.menuClosedSlideAllowed(dx);  
  566.         }  
  567. if
  568. "this slide allowed " + allowed + " dx: "
  569. return
  570.     }  
  571.   
  572. private int getPointerIndex(MotionEvent ev, int
  573. int
  574. if (activePointerIndex == -1)  
  575.             mActivePointerId = INVALID_POINTER;  
  576. return
  577.     }  
  578.   
  579. private boolean mQuickReturn = false;  
  580.   
  581. @Override
  582. public boolean
  583.   
  584. if
  585. return false;  
  586.   
  587. final int
  588.   
  589. if
  590. if
  591. "Received ACTION_DOWN");  
  592.   
  593. if
  594.                 || (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) {  
  595.             endDrag();  
  596. return false;  
  597.         }  
  598.   
  599. switch
  600. case
  601.             determineDrag(ev);  
  602. break;  
  603. case
  604. int
  605.             mActivePointerId = MotionEventCompat.getPointerId(ev, index);  
  606. if
  607. break;  
  608.             mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, index);  
  609.             mLastMotionY = MotionEventCompat.getY(ev, index);  
  610. if
  611. false;  
  612. false;  
  613. if
  614. true;  
  615.                 }  
  616. else
  617. true;  
  618.             }  
  619. break;  
  620. case
  621.             onSecondaryPointerUp(ev);  
  622. break;  
  623.         }  
  624.   
  625. if
  626. if (mVelocityTracker == null) {  
  627.                 mVelocityTracker = VelocityTracker.obtain();  
  628.             }  
  629.             mVelocityTracker.addMovement(ev);  
  630.         }  
  631. return
  632.     }  
  633.   
  634.   
  635. @Override
  636. public boolean
  637.   
  638. if
  639. return false;  
  640.   
  641. if
  642. return false;  
  643.   
  644. //      if (!mIsBeingDragged && !mQuickReturn)
  645. //          return false;
  646.   
  647. final int
  648.   
  649. if (mVelocityTracker == null) {  
  650.             mVelocityTracker = VelocityTracker.obtain();  
  651.         }  
  652.         mVelocityTracker.addMovement(ev);  
  653.   
  654. switch
  655. case
  656. /*
  657.              * If being flinged and user touches, stop the fling. isFinished
  658.              * will be false if being flinged.
  659.              */
  660.             completeScroll();  
  661.   
  662. // Remember where the motion event started
  663. int
  664.             mActivePointerId = MotionEventCompat.getPointerId(ev, index);  
  665.             mLastMotionX = mInitialMotionX = ev.getX();  
  666. break;  
  667. case
  668. if
  669.                 determineDrag(ev);  
  670. if
  671. return false;  
  672.             }  
  673. if
  674. // Scroll to follow the motion event
  675. final int
  676. if
  677. break;  
  678. final float
  679. final float
  680.                 mLastMotionX = x;  
  681. float
  682. float
  683. final float
  684. final float
  685. if
  686.                     scrollX = leftBound;  
  687. else if
  688.                     scrollX = rightBound;  
  689.                 }  
  690. // Don't lose the rounded component
  691. int) scrollX;  
  692. int) scrollX, getScrollY());  
  693. int) scrollX);  
  694.             }  
  695. break;  
  696. case
  697. if
  698. final
  699. 1000, mMaximumVelocity);  
  700. int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(  
  701.                         velocityTracker, mActivePointerId);  
  702. final int
  703. final float pageOffset = (float) (scrollX - getDestScrollX(mCurItem)) / getBehindWidth();  
  704. final int
  705. if
  706. final float
  707. final int totalDelta = (int) (x - mInitialMotionX);  
  708. int
  709. true, true, initialVelocity);  
  710. else
  711. true, true, initialVelocity);  
  712.                 }  
  713.                 mActivePointerId = INVALID_POINTER;  
  714.                 endDrag();  
  715. else if
  716. // close the menu
  717. 1);  
  718.                 endDrag();  
  719.             }  
  720. break;  
  721. case
  722. if
  723. true, true);  
  724.                 mActivePointerId = INVALID_POINTER;  
  725.                 endDrag();  
  726.             }  
  727. break;  
  728. case
  729. final int
  730.             mLastMotionX = MotionEventCompat.getX(ev, indexx);  
  731.             mActivePointerId = MotionEventCompat.getPointerId(ev, indexx);  
  732. break;  
  733.         }  
  734. case
  735.             onSecondaryPointerUp(ev);  
  736. int
  737. if
  738. break;  
  739.             mLastMotionX = MotionEventCompat.getX(ev, pointerIndex);  
  740. break;  
  741.         }  
  742. return true;  
  743.     }  
  744.       
  745. private void
  746. final int
  747. final int
  748. if
  749. return;  
  750. final float
  751. final float
  752. final float
  753. final float
  754. final float
  755. final float
  756. if (xDiff > (isMenuOpen()?mTouchSlop/2:mTouchSlop) && xDiff > yDiff && thisSlideAllowed(dx)) {          
  757.             startDrag();  
  758.             mLastMotionX = x;  
  759.             mLastMotionY = y;  
  760. true);  
  761. // TODO add back in touch slop check
  762. else if
  763. true;  
  764.         }  
  765.     }  
  766.   
  767. @Override
  768. public void scrollTo(int x, int
  769. super.scrollTo(x, y);  
  770.         mScrollX = x;  
  771.         mViewBehind.scrollBehindTo(mContent, x, y);   
  772.        ((SlidingMenu)getParent()).manageLayers(getPercentOpen());  
  773.           
  774. if (mTransformer != null) {  
  775.             invalidate();  
  776.         }  
  777.     }  
  778.   
  779. private int determineTargetPage(float pageOffset, int velocity, int
  780. int
  781. if
  782. if (velocity > 0 && deltaX > 0) {  
  783. 1;  
  784. else if (velocity < 0 && deltaX < 0){  
  785. 1;  
  786.             }  
  787. else
  788. int) Math.round(mCurItem + pageOffset);  
  789.         }  
  790. return
  791.     }  
  792.   
  793. protected float
  794. return
  795.     }  
  796.   
  797. @Override
  798. protected void
  799. // 这句要注释掉,否则会出现2个右侧的视图,一个有转场动画,一个没有转场动画
  800. // super.dispatchDraw(canvas);
  801. // Draw the margin drawable if needed.
  802.         mViewBehind.drawShadow(mContent, canvas);  
  803.         mViewBehind.drawFade(mContent, canvas, getPercentOpen());  
  804.         mViewBehind.drawSelector(mContent, canvas, getPercentOpen());  
  805. // 设置右侧视图的转场效果,主要是修改Canvas。
  806. if (mTransformer != null) {  
  807.             canvas.save();  
  808.             mTransformer.transformCanvas(canvas, getPercentOpen());  
  809. super.dispatchDraw(canvas);  
  810.             canvas.restore();  
  811. else
  812. super.dispatchDraw(canvas);  
  813.         }  
  814.     }  
  815.   
  816. // variables for drawing
  817. private float mScrollX = 0.0f;  
  818.   
  819. private void
  820. if (DEBUG) Log.v(TAG, "onSecondaryPointerUp called");  
  821. final int
  822. final int
  823. if
  824. // This was our active pointer going up. Choose a new
  825. // active pointer and adjust accordingly.
  826. final int newPointerIndex = pointerIndex == 0 ? 1 : 0;  
  827.             mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);  
  828.             mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);  
  829. if (mVelocityTracker != null) {  
  830.                 mVelocityTracker.clear();  
  831.             }  
  832.         }  
  833.     }  
  834.   
  835. private void
  836. true;  
  837. false;  
  838.     }  
  839.   
  840. private void
  841. false;  
  842. false;  
  843. false;  
  844.         mActivePointerId = INVALID_POINTER;  
  845.   
  846. if (mVelocityTracker != null) {  
  847.             mVelocityTracker.recycle();  
  848. null;  
  849.         }  
  850.     }  
  851.   
  852. private void setScrollingCacheEnabled(boolean
  853. if
  854.             mScrollingCacheEnabled = enabled;  
  855. if
  856. final int
  857. for (int i = 0; i < size; ++i) {  
  858. final
  859. if
  860.                         child.setDrawingCacheEnabled(enabled);  
  861.                     }  
  862.                 }  
  863.             }  
  864.         }  
  865.     }  
  866.   
  867. /**
  868.      * Tests scrollability within child views of v given a delta of dx.
  869.      *
  870.      * @param v View to test for horizontal scrollability
  871.      * @param checkV Whether the view v passed should itself be checked for scrollability (true),
  872.      *               or just its children (false).
  873.      * @param dx Delta scrolled in pixels
  874.      * @param x X coordinate of the active touch point
  875.      * @param y Y coordinate of the active touch point
  876.      * @return true if child views of v can be scrolled by delta of dx.
  877.      */
  878. protected boolean canScroll(View v, boolean checkV, int dx, int x, int
  879. if (v instanceof
  880. final
  881. final int
  882. final int
  883. final int
  884. // Count backwards - let topmost views consume scroll distance first.
  885. for (int i = count - 1; i >= 0; i--) {  
  886. final
  887. if
  888.                         y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&  
  889. true, dx, x + scrollX - child.getLeft(),  
  890.                                 y + scrollY - child.getTop())) {  
  891. return true;  
  892.                 }  
  893.             }  
  894.         }  
  895.   
  896. return
  897.     }  
  898.   
  899.   
  900. @Override
  901. public boolean
  902. // Let the focused view and/or our descendants get the key first
  903. return super.dispatchKeyEvent(event) || executeKeyEvent(event);  
  904.     }  
  905.   
  906. /**
  907.      * You can call this function yourself to have the scroll view perform
  908.      * scrolling from a key event, just as if the event had been dispatched to
  909.      * it by the view hierarchy.
  910.      *
  911.      * @param event The key event to execute.
  912.      * @return Return true if the event was handled, else false.
  913.      */
  914. public boolean
  915. boolean handled = false;  
  916. if
  917. switch
  918. case
  919.                 handled = arrowScroll(FOCUS_LEFT);  
  920. break;  
  921. case
  922.                 handled = arrowScroll(FOCUS_RIGHT);  
  923. break;  
  924. case
  925. if (Build.VERSION.SDK_INT >= 11) {  
  926. // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD
  927. // before Android 3.0. Ignore the tab key on those devices.
  928. if
  929.                         handled = arrowScroll(FOCUS_FORWARD);  
  930. else if
  931.                         handled = arrowScroll(FOCUS_BACKWARD);  
  932.                     }  
  933.                 }  
  934. break;  
  935.             }  
  936.         }  
  937. return
  938.     }  
  939.   
  940. public boolean arrowScroll(int
  941.         View currentFocused = findFocus();  
  942. if (currentFocused == this) currentFocused = null;  
  943.   
  944. boolean handled = false;  
  945.   
  946. this, currentFocused,  
  947.                 direction);  
  948. if (nextFocused != null
  949. if
  950.                 handled = nextFocused.requestFocus();  
  951. else if
  952. // If there is nothing to the right, or this is causing us to
  953. // jump to the left, then what we really want to do is page right.
  954. if (currentFocused != null
  955.                     handled = pageRight();  
  956. else
  957.                     handled = nextFocused.requestFocus();  
  958.                 }  
  959.             }  
  960. else if
  961. // Trying to move left and nothing there; try to page.
  962.             handled = pageLeft();  
  963. else if
  964. // Trying to move right and nothing there; try to page.
  965.             handled = pageRight();  
  966.         }  
  967. if
  968.             playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));  
  969.         }  
  970. return
  971.     }  
  972.   
  973. boolean
  974. if (mCurItem > 0) {  
  975. 1, true);  
  976. return true;  
  977.         }  
  978. return false;  
  979.     }  
  980.   
  981. boolean
  982. if (mCurItem < 1) {  
  983. 1, true);  
  984. return true;  
  985.         }  
  986. return false;  
  987.     }  
  988.       
  989. public void
  990.         mTransformer = t;  
  991.     }  
  992.       
  993. }  

如果想要使用这个侧滑菜单的动画效果,直接替换这两个类即可。同时,并不会影响SlidingMenu的固有功能。

下面看看如何配置SlidingMenu实例。


[java] ​​ view plain​​ ​​c


  1. SlidingMenu sm = getSlidingMenu();  
  2. sm.setBehindOffsetRes(R.dimen.slidingmenu_offset);  
  3. sm.setFadeEnabled(false);  
  4. sm.setBehindScrollScale(0.25f);  
  5. sm.setFadeDegree(0.25f);  
  6.   
  7. // 配置背景图片
  8. sm.setBackgroundImage(R.drawable.img_frame_background);  
  9. // 设置专场动画效果
  10. sm.setBehindCanvasTransformer(new
  11. @Override
  12. public void transformCanvas(Canvas canvas, float
  13. float scale = (float) (percentOpen * 0.25 + 0.75);  
  14. 2,  
  15. 2);  
  16.     }  
  17. });  
  18.   
  19. sm.setAboveCanvasTransformer(new
  20. @Override
  21. public void transformCanvas(Canvas canvas, float
  22. float scale = (float) (1 - percentOpen * 0.25);  
  23. 0, canvas.getHeight() / 2);  
  24.     }  
  25. });