36

I am playing around with DrawerLayout and I am encountering an issue. Basically sometimes when i swipe from the edge of the screen the DrawerLayout will get stuck until i lift my finger off the screen (See screenshot below)

I am not sure what is up, I followed the code sample from the google sdk exactly. Any ideas?

Screenshot bug

And here is the only thing i have in my FragmentActivity:

@Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final String[] names =
                getResources().getStringArray(R.array.nav_names);
        ArrayAdapter<String> adapter =
                new ArrayAdapter<String>(
                        getActionBar().getThemedContext(),
                        android.R.layout.simple_list_item_1, names);

        final DrawerLayout drawer =
                (DrawerLayout)findViewById(R.id.drawer_layout);
        final ListView navList =
                (ListView) findViewById(R.id.drawer);
        navList.setAdapter(adapter);
        navList.setOnItemClickListener(new AdapterView.OnItemClickListener()
        {

            @Override
            public void onItemClick(AdapterView<?> parent,
                                    View view, final int pos, long id)
            {
                drawer.setDrawerListener(
                        new DrawerLayout.SimpleDrawerListener()
                        {
                            @Override
                            public void onDrawerClosed(View drawerView)
                            {
                                super.onDrawerClosed(drawerView);

                            }
                        });
                drawer.closeDrawer(navList);
            }
        });

    }

EDIT:I'm adding a bounty on this, as this is a very old issue that exists even today with the latest Android-X (sample available here). Here's how it looks:

enter image description here

I've reported about it to Google (here and later again here), but it didn't help.

I've tried all existing solutions here on this thread, and none worked. If anyone has a good workaround for this (while still using DrawerLayout or extending it, or something similar), please put a working solution.

android developer
  • 114,585
  • 152
  • 739
  • 1,270
thunderousNinja
  • 3,510
  • 9
  • 37
  • 49
  • 2
    I think it's a bug. I have the same bug with Gingerbread. Tested on Nexus 7 and I could't reproduce this. – vovahost Aug 03 '13 at 08:02
  • Weird. I am on version 4.2 – thunderousNinja Aug 03 '13 at 23:50
  • 1
    are you sure it's not a feature? Doc: `If the user touches the very left edge of the screen (within 20 dp from the left), have the drawer peek out as soon as the finger makes contact with the display. This promotes accidental discovery and provides richer feedback.` – Zyoo Sep 30 '13 at 05:06
  • I am pretty sure it is not a feature as the same behavior does not happen on other apps that use the drawer layout (e.g. gmail, google music). – thunderousNinja Sep 30 '13 at 16:38
  • Indeed it is a feature as Zyoo suggested. Take a look at http://developer.android.com/design/patterns/navigation-drawer.html – Akos Cz Nov 16 '13 at 07:33
  • 2
    It is not a feature. I try to explain the difference: The peek out feature works by clicking on the left side and gives a feedback that there is something to pull out -> the nav drawer. What unknown and I encounter is a bug: It peeks out, but then you can't pull it out. This is not intended! – Dominik Schürmann Feb 21 '14 at 19:12
  • 2
    The issue still exists in the latest support library version 21.0.1 – Ahmed Hegazy Nov 13 '14 at 07:36
  • Issue exists even on Android X library. I've put a bounty in case anyone knows how to really fix it. – android developer Nov 23 '18 at 08:51
  • @androiddeveloper: The `MyApplication.7z` file is not downloadable. Is it possible to you to share it another way? – aminography Nov 23 '18 at 16:26
  • @aminography It is downloadable just fine. Maybe something is wrong on your web browser, or you block something. You have to choose "MyApplication.7z ", as it says "To download file click the link below: " . Also, as I've mentioned, it's easy to create such a project. It's from the wizard of the IDE. I didn't change their anything related to the topic. – android developer Nov 24 '18 at 00:23
  • 1
    @androiddeveloper this issue exists even in the Google Play app, I don't think we are able to fix it – Roman Samoilenko Dec 04 '18 at 07:29
  • @RomanSamoylenko You are correct. I thought it was somehow fixed there. I've reproduced it now, but later couldn't. I don't get why and when it occurs. Can you please tell me if you succeed to reproduce it in a more consistent way? Also, could you please publish a video of it occur on the Play Store, here: https://issuetracker.google.com/issues/37126887 . – android developer Dec 04 '18 at 07:32
  • 1
    @androiddeveloper yeah, it's quite hard to reproduce, but it has a consistent behavior of getting stuck at the same offset. I uploaded the video to the issue tracker – Roman Samoilenko Dec 04 '18 at 08:27
  • @RomanSamoylenko Thank you. I hope they will fix it. I've noticed it a very long time ago. – android developer Dec 04 '18 at 09:52
  • After such a long time, the issue still remains there. Is there a github issue or something for this? I don't see such behavior in many apps on play store including Play Store. Any new discoveries as what is the true cause for this and resolutions? – Akash Gorai Aug 16 '20 at 14:08

5 Answers5

16

Note that you can get around this 20dp peek feature by setting the clickable attribute to true on the FrameLayout within the DrawerLayout.

android:clickable="true"

for instance : http://developer.android.com/training/implementing-navigation/nav-drawer.html

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true" />
    <!-- The navigation drawer -->
    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/darker_gray"
        android:dividerHeight="1dp" />
</android.support.v4.widget.DrawerLayout>
Akos Cz
  • 12,711
  • 1
  • 37
  • 32
0

If you had shown us your layout xml, we could see if you have DrawerLayout as ROOT element. And whether the inside two children are Main Layout and Navigation Drawer.

According to Create a Drawer Layout:

To add a navigation drawer, declare your user interface with a DrawerLayout object as the root view of your layout. Inside the DrawerLayout, add one view that contains the main content for the screen (your primary layout when the drawer is hidden) and another view that contains the contents of the navigation drawer.

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Wenza
  • 37
  • 8
  • Wenza, have a look at the [revisions](http://stackoverflow.com/posts/32355754/revisions) for your answer. I had to guess a bit at what you were saying, so correct it if I have it wrong. But don't use answers to ask questions - work on earning the privilege to post comments. – Mogsdad Sep 02 '15 at 14:38
  • Hello, the answer was to have drawerlayout as root and inside two elements. The question was additional. – Wenza Sep 08 '15 at 09:46
  • No need to show anything. This issue exists even on a totally new project that has the drawer from the start, via the wizard of the IDE. – android developer Dec 08 '18 at 10:13
  • Also, if you really wish, I've posted a sample project. – android developer Dec 12 '18 at 08:07
0

I've managed to work around this by implementing this DrawerListener:

drawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
            @Override
            public void onDrawerStateChanged(int newState) {
                super.onDrawerStateChanged(newState);
                if (drawerLayout.isDrawerVisible(Gravity.LEFT) && !drawerLayout.isDrawerOpen(Gravity.LEFT)) {
                    drawerLayout.closeDrawer(Gravity.LEFT);
                }
            }
        });

Whenever the state changes, if the drawer is visible but not open, it means it's 'peeking', so I close it.

bernardo.g
  • 826
  • 1
  • 12
  • 27
  • This makes the behavior much worse. Now every time the drawer is not completely opened, it gets closed. Need to drag it all the way to the right to make it opened. – android developer Dec 08 '18 at 10:14
0

This 20dp Peek feature can be achieved When user drags the drawer to 20dp than open the drawer. Here is code working fine for me.

class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {


lateinit var mToggle: ActionBarDrawerToggle
lateinit var mDrawerLayout: DrawerLayout

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val toolbar: Toolbar = findViewById(R.id.toolbar)
    setSupportActionBar(toolbar)

    val fab: FloatingActionButton = findViewById(R.id.fab)
    fab.setOnClickListener { view ->
        Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
            .setAction("Action", null).show()
    }

    mDrawerLayout = findViewById(R.id.drawer_layout)
    val navView: NavigationView = findViewById(R.id.nav_view)

    mToggle = ActionBarDrawerToggle(
        this, mDrawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close
    )
    mDrawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
        override fun onDrawerStateChanged(newState: Int) {
            Log.d("onDrawerStateChanged", "$newState")
            mToggle.onDrawerStateChanged(newState)
        }

        override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
            if ((slideOffset >= (dpToPx(19.9f)/drawerView.width)) && (slideOffset <= (dpToPx(20.1f)/drawerView.width))){
                Log.d("onDrawerSlide", "true")
                mDrawerLayout.openDrawer(GravityCompat.START)
            }
            Log.d("onDrawerSlide", "$slideOffset")
            mToggle.onDrawerSlide(drawerView,slideOffset)
        }

        override fun onDrawerClosed(drawerView: View) {
            mToggle.onDrawerClosed(drawerView)
        }

        override fun onDrawerOpened(drawerView: View) {
            mToggle.onDrawerOpened(drawerView)
        }

    })

    mToggle.syncState()

    navView.setNavigationItemSelectedListener(this)
}

override fun onBackPressed() {
    val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
    if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
        drawerLayout.closeDrawer(GravityCompat.START)
    } else {
        super.onBackPressed()
    }
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    // Inflate the menu; this adds items to the action bar if it is present.
    menuInflater.inflate(R.menu.main, menu)
    return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    return when (item.itemId) {
        R.id.action_settings -> true
        else -> super.onOptionsItemSelected(item)
    }
}

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    // Handle navigation view item clicks here.
    when (item.itemId) {
        R.id.nav_home -> {
            // Handle the camera action
        }
        R.id.nav_gallery -> {

        }
        R.id.nav_slideshow -> {

        }
        R.id.nav_tools -> {

        }
        R.id.nav_share -> {

        }
        R.id.nav_send -> {

        }
    }
    val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
    drawerLayout.closeDrawer(GravityCompat.START)
    return true
}

fun dpToPx(dps : Float) : Float{
    return (dps * Resources.getSystem().displayMetrics.density)
}

}

Muzammil Husnain
  • 1,218
  • 1
  • 10
  • 24
0

I can't comment, but the highest voted answer works for me on Android 11. I did it like this:

<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:openDrawer="start">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true"
        android:focusable="true" >
        <include
            layout="@layout/main_activity"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/side_nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:menu="@menu/side_nav_menu"/>

</androidx.drawerlayout.widget.DrawerLayout>
TimB
  • 493
  • 3
  • 16