How to show the DrawerLayout when sliding from left to right, no matter where?

南笙酒味 提交于 2019-12-18 04:14:48

问题


background

google has introduced the DrawerLayout, which shows a menu on the left area of the screen when you click on the "up" button of the action bar.

because the library isn't supported yet on actionBarSherlock, there is already a way to overcome it using this project .

it already has variants on many apps: currents, gmail, hangouts, youtube...

the question

on the "currents" app (and in youtube) , when the user slides the (most-left) page from left to right , the DrawerLayout appears, no matter where the finger has started the touch .

how can i achieve the same effect? maybe i should use onInterceptTouchEvent ?

there isn't much documentation and tutorials of what cool things can be done , other than this link (ok and this one too) . they say (in the part of "Give the user a quick peek") that about 20dp on the left is used for this functionality, but i can see that "currents" work with much larger area.

it seems the library is still not quite finished, and so the layout xml file cannot even be shown in the visual UI editor...


EDIT: it seems that the library is open sourced. code is available on :

.../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

now the question is how to make it work as i've written, so that it would work like on youtube , allowing us to customize how it looks and from where to allow scrolling it.


回答1:


SlidingMenu is best sliding library I've ever found, It's very good library.
You can set getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN) enabling fling for all screen.




回答2:


The problem is that DrawerLayout uses ViewDragHelper which has a default EDGE_SIZE of 20dp which is used to calculate the mEdgeSize like this:

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

Here is a function which sets mEdgeSize to a percentage of the display width:

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
    }
}

So, let's say you want 30% of your left edge to react to slide events and open the Navigation Drawer, then simply call:

mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
setDrawerLeftEdgeSize(this, mDrawerLayout, 0.3f);



回答3:


I tried changing default EDGE_SIZE solution, and encountered the long clicking problem too. Finally, Ifound override dispatchTouchEvent and open drawer depending the sliding direction by calculating X offset.

@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;
    }



回答4:


By using others' help: (first) (second)

I found that using reflections it's achievable to modify the defult 20dp-screen-edge for the drawer menu to slide

After declaring content and drawers, you can do this:

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);

}
}

Well, It works for me man!




回答5:


You can use this with Navigation Drawer

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); 



回答6:


Using this project SlidingMenu you can achieve that effect and integrate with ActionBarSherlock.

To slide the menu from left to right just customize the menu when creating it and add:

slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);

Hope this helps.




回答7:


Firstly I am not sure what you mean about ActionBarSherlock not supporting DrawerLayout. You can work with the DrawerLayout and ActionBarSherlock quite happily, I have apps that are using this combination. You will need to change the support jar version but I have found that ActionbarSherlock does not have a problem with this.

Implement DrawerLayout in the usual manner. Then in your fragment implement onTouchEvent or interceptTouchEvent and when the type is a 'move' type event sliding from left to right you can call the openDrawer method on the DrawerLayout. You will need to add handling for the distance the finger travels to make sure the call to open the drawer is not too sensitive.




回答8:


When we override the default edge side our screen of that portion on which it overlaps stops working, I have used the above code in viewpager but now when i scroll to the left from right instead of coming next view page it remains constant. What will be the solution for it? I have used 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
        }
    }

same as above..



来源:https://stackoverflow.com/questions/17699869/how-to-show-the-drawerlayout-when-sliding-from-left-to-right-no-matter-where

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!