无需SherlockActionbar的SlidingMenu使用详解(一)——通过SlidingMenu设置容器并解决滑动卡顿的问题

 

  想必很多人都听过这个开源框架,一年前真的是风靡一时。只是它的配置较为繁琐,还需要sherlockActionbar的支持,我这里下载了最新的开源库,并且在实际用套用了AppCompat的官方库,这样就完全不用sherlockActionbar的支持啦~ 

SlidingMenu官方下载地址:https://github.com/jfeinstein10/SlidingMenu

先大概讲解下配置:

下载库library,然后倒入到编译器中,并且添加依赖。这里可能会出现v4包不同的问题,总之换为最新的即可!

本篇讲解的是这个项目的简单配置,为以后做准备。咱们先来看看怎么来初步使用这个控件。

一、思路

1. 建立一个主界面的布局和菜单界面的布局

1.1 主界面

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content_frame_id"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

1.2 菜单界面

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/menu_frame_id"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

可以看出都是超级简单的布局,这两个就是为以后放fragment做准备的容器。

二、在Actiivity或者主布局文件中设置SlidingMenu控件

这里我不推荐在xml文件中定义,原因是有bug。

2.1 在activity中初始化slidingmenu

  private SlidingMenu menu;
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 设置正文容器
        setContentView(R.layout.content_frame);
// 用代码来设置抽屉菜单
        setSlidingMenu();

    }
    /**
     * slidingMenu属性详解
     */
    protected void setSlidingMenu() {
        // configure the SlidingMenu
        menu = new SlidingMenu(this);
        menu.setMode(SlidingMenu.LEFT);
        menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
        // 设置边缘阴影的宽度,通过dimens资源文件中的ID设置
        menu.setShadowWidthRes(R.dimen.slidingmenu_shadow_width);
        // 设置阴影的图片
        menu.setShadowDrawable(R.drawable.shadow);
        // 设置偏移量。说明:设置menu全部打开后,主界面剩余部分与屏幕边界的距离,值写在dimens里面:60dp
        menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
        // 设置是否淡入淡出
        menu.setFadeEnabled(true);
        // 设置淡入淡出的值,只在setFadeEnabled设置为true时有效
        menu.setFadeDegree(0.5f);
        // 全屏:TOUCHMODE_FULLSCREEN ;边缘:TOUCHMODE_MARGIN ;不打开:TOUCHMODE_NONE
        menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
        // 设置滑动时actionbar是否跟着移动,SLIDING_WINDOW=跟着移动;SLIDING_CONTENT=不跟着移动
        menu.attachToActivity(this, SlidingMenu.SLIDING_WINDOW);
        // 设置滑动方向
        menu.setMode(SlidingMenu.LEFT);
        // 设置menu的背景
        // menu.setBackgroundColor(getResources().getColor(android.R.color.background_dark));
        // 设置菜单容器,注意这里只是容器,而不是菜单的界面
        menu.setMenu(R.layout.menu_frame);
    }

    public SlidingMenu getMySlidingMenu() {
        return menu;
    }

附上官网的example:

public class SlidingExample extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle(R.string.attach);
        // set the content view
        setContentView(R.layout.content);
        // configure the SlidingMenu
        SlidingMenu menu = new SlidingMenu(this);
        menu.setMode(SlidingMenu.LEFT);
        menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
        menu.setShadowWidthRes(R.dimen.shadow_width);
        menu.setShadowDrawable(R.drawable.shadow);
        menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
        menu.setFadeDegree(0.35f);
        menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
        menu.setMenu(R.layout.menu);
    }

}

这里initSlidingMenu做的事情就是在主布局文件中建立一个SlidingMenu控件,并且这个控件通过setMenu方法扩展了一个Menu的容器。

这样你的布局文件中其实是有两个布局了,一个是通过setContentView(R.layout.content_frame);正常设置的布局,一个是通过slidingMenu.setMenu(R.layout.menu_frame);设置的菜单布局。这里的两个布局就是我们上面定义的布局。OK,现在我们拥有了两个布局容器,就可以往里面放Fragment了。

2.2 通过xml文件设置,虽然有bug,但我还是注释下。

官网:

If you decide to use SlidingMenu as a view, you can define it in your xml layouts like this:

<com.jeremyfeinstein.slidingmenu.lib.SlidingMenu
    xmlns:sliding="http://schemas.android.com/apk/res-auto"
    android:id="@+id/slidingmenulayout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    sliding:viewAbove="@layout/YOUR_ABOVE_VIEW"
    sliding:viewBehind="@layout/YOUR_BEHIND_BEHIND"
    sliding:touchModeAbove="margin|fullscreen"
    sliding:behindOffset="@dimen/YOUR_OFFSET"
    sliding:behindWidth="@dimen/YOUR_WIDTH"
    sliding:behindScrollScale="@dimen/YOUR_SCALE"
    sliding:shadowDrawable="@drawable/YOUR_SHADOW"
    sliding:shadowWidth="@dimen/YOUR_SHADOW_WIDTH"
    sliding:fadeEnabled="true|false"
    sliding:fadeDegree="float"
    sliding:selectorEnabled="true|false"
    sliding:selectorDrawable="@drawable/YOUR_SELECTOR"/>

NOTE : you cannot use both behindOffset and behindWidth. You will get an exception if you try.

  • viewAbove - a reference to the layout that you want to use as the above view of the SlidingMenu
  • viewBehind - a reference to the layout that you want to use as the behind view of the SlidingMenu
  • touchModeAbove - an enum that designates what part of the screen is touchable when the above view is showing. Margin means only the left margin. Fullscreen means the entire screen. Default is margin.
  • behindOffset - a dimension representing the number of pixels that you want the above view to show when the behind view is showing. Default is 0.
  • behindWidth - a dimension representing the width of the behind view. Default is the width of the screen (equivalent to behindOffset = 0).
  • behindScrollScale - a float representing the relationship between the above view scrolling and the behind behind view scrolling. If set to 0.5f, the behind view will scroll 1px for every 2px that the above view scrolls. If set to 1.0f, the behind view will scroll 1px for every 1px that the above view scrolls. And if set to 0.0f, the behind view will never scroll; it will be static. This one is fun to play around with. Default is 0.25f.
  • shadowDrawable - a reference to a drawable to be used as a drop shadow from the above view onto the below view. Default is no shadow for now.
  • shadowWidth - a dimension representing the width of the shadow drawable. Default is 0.
  • fadeEnabled - a boolean representing whether or not the behind view should fade when the SlidingMenu is closing and "un-fade" when opening
  • fadeDegree - a float representing the "amount" of fade. 1.0f would mean fade all the way to black when the SlidingMenu is closed. 0.0f would mean do not fade at all.
  • selectorEnabled - a boolean representing whether or not a selector should be drawn on the left side of the above view showing a selected view on the behind view.
  • selectorDrawable - a reference to a drawable to be used as the selector NOTE : in order to have the selector drawn, you must call SlidingMenu.setSelectedView(View v) with the selected view. Note that this will most likely not work with items in a ListView because of the way that Android recycles item views.

我自己的注释:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <!-- 
    mode:设置抽屉的打开方向,可以设置左右或同时left|right
    behindOffset:设置打开抽屉后主界面距离屏幕的距离
    fadeEnabled:允许淡入淡出
    fadeDegree:淡入淡出的度数,这个在fadeEnable = true时有效
    shadowDrawable:阴影的图片
    shadowWidth:阴影宽度,这里要在dimen中设置
    touchModeAbove:滑动打开抽屉的范围,可以选择:"fullscreen"=全屏,"margin"=边缘打开
    viewAbove:在主页面上方的图片 
    viewBehind:在抽屉界面上方显示的图片。example:sliding:viewBehind="@layout/above_layout" 
     -->
    <com.jeremyfeinstein.slidingmenu.lib.SlidingMenu
        xmlns:sliding="http://schemas.android.com/apk/res-auto"
        android:id="@+id/slidingmenulayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        sliding:viewBehind="@layout/menu_frame"
        sliding:viewAbove="@layout/content_frame"
        sliding:mode="left"
        sliding:behindOffset="@dimen/slidingmenu_offset"
        sliding:fadeEnabled="true"
        sliding:fadeDegree="0.5"
        sliding:shadowDrawable="@drawable/shadow"
        sliding:shadowWidth="@dimen/slidingmenu_shadow_width"
        sliding:touchModeAbove="fullscreen"/>

</RelativeLayout>

这里可以明确的看到在xml文件中有这个布局,并且这个布局通过viewBehind、viewAbove设置两个布局。其实就是一个主布局,主布局中include了两个其他的布局文件。

在Activity中获取到控件,就可以使用啦。注意:这里setContentView设置的布局是有slidingmenu的main_activity.xml

setContentView(R.layout.activity_main);
//在主界面的布局文件中设置slidingMenu
initSlidingMenu();

    private void initSlidingMenu() {
        menu = (SlidingMenu) findViewById(R.id.slidingmenulayout);
    }

三、加载Fragment

现在我们可以往里面加载Fragment了,这里有用到个小技巧来存放当前的fragment对象

    //通过数字来标识当前是哪个fragment,这样用于加载顶部的menu
    public static int NOW_FRAGMENT_NO = 0;
    
    private Fragment nowFragment;
    private SlidingMenu menu;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 设置正文容器
        setContentView(R.layout.content_frame);
        // 设置左上角的按钮可以点击
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setBackgroundDrawable(getResources().getDrawable(R.drawable.bar_color));
        // 用代码来设置抽屉菜单
        setSlidingMenu();
        /*setContentView(R.layout.activity_main);
        //在主界面的布局文件中设置slidingMenu
        initSlidingMenu();*/

        if (savedInstanceState != null) {
            nowFragment = getSupportFragmentManager().getFragment( 
                    savedInstanceState, "mContent");
        }
        // 默认载入的fragment
        else {
            nowFragment = new FirstFragment();
        }
        initFragment();
    }
@Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        getSupportFragmentManager().putFragment(outState, "mContent", nowFragment);
    }
   /**
     * 填入主界面和菜单的Fragment
     */
    private void initFragment() {
        // 设置正文容器
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.content_frame_id, nowFragment).commit();

        // 设置菜单容器,这里用到了AppMenuFragment()
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.menu_frame_id, new MenuFragment()).commit();
    }

四、切换Fragment的方法

因为我们通常是随着menu菜单的点击来切换fragment的,所以切换的方法需要写到activity才能对slidingmenu进行完全的控制。此外,我们一般对Menu界面是不需要进行切换的,主要是切换正文的fragment。

    /**
     * 切换正文fragment
     * 
     * @param fragment
     */
    public void switchContent(Fragment fragment) {
        // 切换回默认样式
        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        // 切换界面前清空tab
        getSupportActionBar().removeAllTabs();
        // 切换回默认的触控范围(全屏滑动有效)
        getMySlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
        
        nowFragment = fragment;
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.content_frame_id, fragment).commit();
        /**
         * 优化的代码,通过handler来避免滑动卡顿的情况。方法:延迟加载抽屉
         * 如果不优化也可以运行,就是将下面的代码改为:menu.showContent();
         */
        Handler h = new Handler();
        h.postDelayed(new Runnable() {
            public void run() {
                menu.showContent();
            }
        }, 50);
    }

下篇:http://www.cnblogs.com/tianzhijiexian/p/3994329.html

原文地址:https://www.cnblogs.com/tianzhijiexian/p/3994197.html