8

背景

google 引入了 DrawerLayout,当你点击操作栏的“向上”按钮时,它会在屏幕的左侧区域显示一个菜单。

因为在 actionBarSherlock 上还不支持该库,所以已经有一种方法可以使用这个项目来克服它。

它已经在许多应用程序上提供了变体:currents、gmail、hangouts、youtube...

问题

在“currents”应用程序(和 youtube)上,当用户从左向右滑动(最左边的)页面时,无论手指从哪里开始触摸,都会出现 DrawerLayout 。

我怎样才能达到同样的效果?也许我应该使用onInterceptTouchEvent

除了这个链接(好的和这个也是)之外,没有太多关于可以做什么很酷的事情的文档和教程。他们说(在“让用户快速浏览”部分)左侧大约 20dp 用于此功能,但我可以看到“电流”适用于更大的区域。

似乎该库还没有完全完成,因此布局 xml 文件甚至无法在可视化 UI 编辑器中显示...


编辑:似乎该库是开源的。代码可用于:

.../android-sdk\sources\android-18\android\support\v4\widget\DrawerLayout.java
.../android-sdk\sources\android-18\android\support\v4\widget\SlidingPaneLayout.java
.../android-sdk\sources\android-18\android\support\v4\app\ActionBarDrawerToggle.java

现在的问题是如何让它像我写的那样工作,这样它就可以像在 youtube 上一样工作,允许我们自定义它的外观以及从哪里允许滚动它。

4

8 回答 8

7

SlidingMenu是我发现的最好的滑动库,非常好的库。
您可以getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN)为所有屏幕设置启用投掷。

于 2013-07-23T16:32:13.020 回答
4

问题是 DrawerLayout 使用 ViewDragHelper,它的默认 EDGE_SIZE为 20dp,用于计算 mEdgeSize,如下所示:

mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);

这是一个将 mEdgeSize 设置为显示宽度百分比的函数:

public static void setDrawerLeftEdgeSize(Activity activity, DrawerLayout drawerLayout, float displayWidthPercentage) {
    if (activity == null || drawerLayout == null)
        return;

    try {
        // find ViewDragHelper and set it accessible
        Field leftDraggerField = drawerLayout.getClass().getDeclaredField("mLeftDragger");
        leftDraggerField.setAccessible(true);
        ViewDragHelper leftDragger = (ViewDragHelper) leftDraggerField.get(drawerLayout);
        // find edgesize and set is accessible
        Field edgeSizeField = leftDragger.getClass().getDeclaredField("mEdgeSize");
        edgeSizeField.setAccessible(true);
        int edgeSize = edgeSizeField.getInt(leftDragger);
        // set new edgesize
        Point displaySize = new Point();
        activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
        edgeSizeField.setInt(leftDragger, Math.max(edgeSize, (int) (displaySize.x * displayWidthPercentage)));
    } catch (NoSuchFieldException e) {
        // ignore
    } catch (IllegalArgumentException e) {
        // ignore
    } catch (IllegalAccessException e) {
        // ignore
    }
}

因此,假设您希望 30% 的左边缘对滑动事件做出反应并打开导航抽屉,然后只需调用:

mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
setDrawerLeftEdgeSize(this, mDrawerLayout, 0.3f);
于 2013-11-14T18:38:33.347 回答
3

我尝试更改默认 EDGE_SIZE 解决方案,也遇到了长按问题。最后,通过计算 X 偏移量,我找到了覆盖 dispatchTouchEvent 并根据滑动方向打开抽屉。

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    int action = ev.getAction();
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            startX = ev.getX();
            startY = ev.getY();
            break;
        case MotionEvent.ACTION_UP:
            endX = ev.getX();
            endY = ev.getY();

            float sensitivity = 5;
            // From left to right
            if (endX - startX >= sensitivity) {
                if (mDrawerLayout.isDrawerOpen(Gravity.RIGHT)) {
                    mDrawerLayout.closeDrawer(Gravity.RIGHT);
                } else {
                    mDrawerLayout.openDrawer(Gravity.LEFT);
                }
            }

            // From right to left
            if (startX - endX >= sensitivity) {
                if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
                    mDrawerLayout.closeDrawer(Gravity.LEFT);
                } else {
                    mDrawerLayout.openDrawer(Gravity.RIGHT);
                }
            }

            break;
    }
于 2014-12-19T07:17:48.780 回答
2

借助他人的帮助:(第一) (第二)

我发现使用反射可以修改默认的 20dp 屏幕边缘以使抽屉菜单滑动

声明内容和抽屉后,您可以这样做:

public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    mDrawerList = (ListView) findViewById(R.id.left_drawer);

    // set a custom shadow that overlays the main content when the drawer opens
    mDrawerLayout.setDrawerShadow(R.drawable.your_drawer_shadow, GravityCompat.START);
    // set up the drawer's list view with items and click listener
    mDrawerList.setAdapter(new ArrayAdapter<String>(this,
            R.layout.your_drawer_list, yourItems));
    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

    // enable ActionBar app icon to behave as action to toggle nav drawer
    getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);

    Field mDragger = null;
    try {
        mDragger = mDrawerLayout.getClass().getDeclaredField(
                "mLeftDragger"); //mRightDragger for right obviously
    } catch (NoSuchFieldException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    mDragger.setAccessible(true);
    ViewDragHelper draggerObj = null;
    try {
        draggerObj = (ViewDragHelper) mDragger
                .get(mDrawerLayout);
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Field mEdgeSize = null;
    try {
        mEdgeSize = draggerObj.getClass().getDeclaredField(
                "mEdgeSize");
    } catch (NoSuchFieldException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    mEdgeSize.setAccessible(true);
    int edge = 0;
    try {
        edge = mEdgeSize.getInt(draggerObj);
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    try {
        mEdgeSize.setInt(draggerObj, edge * 5); //optimal value as for me, you may set any constant in dp
        //You can set it even to the value you want like mEdgeSize.setInt(draggerObj, 150); for 150dp
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    // ActionBarDrawerToggle ties together the the proper interactions
    // between the sliding drawer and the action bar app icon
    mDrawerToggle = new ActionBarDrawerToggle(
            this,                  /* host Activity */
            mDrawerLayout,         /* DrawerLayout object */
            R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */
            R.string.drawer_open,  /* "open drawer" description for accessibility */
            R.string.drawer_close  /* "close drawer" description for accessibility */
            ) {
        public void onDrawerClosed(View view) {

        }

        public void onDrawerOpened(View drawerView) {

        }
    };
    mDrawerLayout.setDrawerListener(mDrawerToggle);

}
}

好吧,它对我有用!

于 2013-07-29T20:13:57.077 回答
2

您可以将其与导航抽屉一起使用

DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
Field mDragger = mDrawerLayout.getClass().getDeclaredField(
    "mLeftDragger");//mRightDragger or mLeftDragger based on Drawer Gravity
mDragger.setAccessible(true);
ViewDragHelper draggerObj = (ViewDragHelper) mDragger
    .get(mDrawerLayout);

Field mEdgeSize = draggerObj.getClass().getDeclaredField(
    "mEdgeSize");
mEdgeSize.setAccessible(true);
int edge = mEdgeSize.getInt(draggerObj);

mEdgeSize.setInt(draggerObj, edge * 3); 
于 2013-11-04T09:21:31.367 回答
1

首先,我不确定您所说的 ActionBarSherlock 不支持 DrawerLayout 是什么意思。您可以非常愉快地使用 DrawerLayout 和 ActionBarSherlock,我有使用这种组合的应用程序。您需要更改支持 jar 版本,但我发现 ActionbarSherlock 对此没有问题。

以通常的方式实现 DrawerLayout。然后在您的片段中实现 onTouchEvent 或 interceptTouchEvent ,当类型是从左向右滑动的“移动”类型事件时,您可以在 DrawerLayout 上调用 openDrawer 方法。您需要为手指移动的距离添加处理,以确保打开抽屉的调用不会太敏感。

于 2013-07-25T09:37:00.940 回答
1

当我们覆盖默认边缘侧时,重叠部分的屏幕停止工作,我在 viewpager 中使用了上面的代码,但现在当我从右向左滚动而不是进入下一个视图页面时,它保持不变。解决方案是什么?我用过setDrawerLeftEdgeSize(this,mDrawerLayout,distance );

public static void setDrawerLeftEdgeSize(Activity activity,
            DrawerLayout drawerLayout, float displayWidthPercentage) {
        if (activity == null || drawerLayout == null)
            return;

        try {
            // find ViewDragHelper and set it accessible
            Field leftDraggerField = drawerLayout.getClass().getDeclaredField(
                    "mLeftDragger");
            leftDraggerField.setAccessible(true);
            ViewDragHelper leftDragger = (ViewDragHelper) leftDraggerField
                    .get(drawerLayout);
            // find edgesize and set is accessible
            Field edgeSizeField = leftDragger.getClass().getDeclaredField(
                    "mEdgeSize");
            edgeSizeField.setAccessible(true);
            int edgeSize = edgeSizeField.getInt(leftDragger);
            // set new edgesize
            Point displaySize = new Point();
            activity.getWindowManager().getDefaultDisplay()
                    .getSize(displaySize);
            edgeSizeField.setInt(leftDragger, Math.max(edgeSize,
                    (int) (displaySize.x * displayWidthPercentage)));
        } catch (NoSuchFieldException e) {
            // ignore
        } catch (IllegalArgumentException e) {
            // ignore
        } catch (IllegalAccessException e) {
            // ignore
        }
    }

和上面一样。。

于 2015-01-06T08:05:02.467 回答
0

使用此项目SlidingMenu,您可以实现该效果并与 ActionBarSherlock 集成。

要从左向右滑动菜单,只需在创建菜单时自定义菜单并添加:

slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);

希望这可以帮助。

于 2013-07-17T12:49:42.923 回答