Unable to create navigation drawer with handle
Asked Answered
E

2

0

I know that this question has been already asked here and here but still I am unable to create the navigation drawer with handle.

I have used the class as mentioned below ::

DrawerHandle ::

@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public class DrawerHandle implements DrawerLayout.DrawerListener {
    public static final String TAG = "DrawerHandle";

    private ViewGroup mRootView;
    private DrawerLayout mDrawerLayout;
    private View mHandle;
    private View mDrawer;

    private float mVerticalOffset;
    private int mGravity;
    private WindowManager mWM;
    private Display mDisplay;
    private Point mScreenDimensions = new Point();

    private OnClickListener mHandleClickListener = new OnClickListener(){

        @Override
        public void onClick(View v) {
            if(!mDrawerLayout.isDrawerOpen(mGravity)) mDrawerLayout.openDrawer(mGravity);
            else mDrawerLayout.closeDrawer(mGravity);
        }

    };

    private OnTouchListener mHandleTouchListener = new OnTouchListener() {
        private static final int MAX_CLICK_DURATION = 200;
        private long startClickTime;
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    startClickTime = System.currentTimeMillis();
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    if(System.currentTimeMillis() - startClickTime < MAX_CLICK_DURATION) {
                        v.performClick();
                        return true;
                    }
                }
            }
            MotionEvent copy = MotionEvent.obtain(event);
            copy.setEdgeFlags(ViewDragHelper.EDGE_ALL);
            copy.setLocation(event.getRawX() + (mGravity == Gravity.LEFT || mGravity == GravityCompat.START ? -mHandle.getWidth()/2 : mHandle.getWidth() / 2), event.getRawY());
            mDrawerLayout.onTouchEvent(copy);
            copy.recycle();
            return true;
        }
    };

    private int getDrawerViewGravity(View drawerView) {
        final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
        return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(drawerView));
    }

    private float getTranslation(float slideOffset){
        return (mGravity == GravityCompat.START || mGravity == Gravity.LEFT) ? slideOffset*mDrawer.getWidth() : -slideOffset*mDrawer.getWidth();
    }

    @SuppressLint("NewApi")
    private void updateScreenDimensions() {

        if (Build.VERSION.SDK_INT >= 13) {
            mDisplay.getSize(mScreenDimensions);
        } else {
            mScreenDimensions.x = mDisplay.getWidth();
            mScreenDimensions.y = mDisplay.getHeight();
        }
    }

    private DrawerHandle(DrawerLayout drawerLayout, View drawer, int handleLayout, float handleVerticalOffset) {
        mDrawer = drawer;
        mGravity = getDrawerViewGravity(mDrawer);
        mDrawerLayout = drawerLayout;
        mRootView = (ViewGroup)mDrawerLayout.getRootView();
        LayoutInflater inflater = (LayoutInflater) mDrawerLayout.getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
        mHandle = inflater.inflate(handleLayout, mRootView, false);
        mWM = (WindowManager) mDrawerLayout.getContext().getSystemService(Context.WINDOW_SERVICE);
        mDisplay = mWM.getDefaultDisplay();

        mHandle.setOnClickListener(mHandleClickListener);   
        mHandle.setOnTouchListener(mHandleTouchListener);
        mRootView.addView(mHandle, new FrameLayout.LayoutParams(mHandle.getLayoutParams().width, mHandle.getLayoutParams().height, mGravity));
        setVerticalOffset(handleVerticalOffset);
        mDrawerLayout.setDrawerListener(this);
    }

    public static DrawerHandle attach(View drawer, int handleLayout, float verticalOffset) {
        if (!(drawer.getParent() instanceof DrawerLayout)) throw new IllegalArgumentException("Argument drawer must be direct child of a DrawerLayout");
        return new DrawerHandle((DrawerLayout)drawer.getParent(), drawer, handleLayout, verticalOffset);
    }

    public static DrawerHandle attach(View drawer, int handleLayout) {
        return attach(drawer, handleLayout, 0);
    }

    @Override
    public void onDrawerClosed(View arg0) {
    }

    @Override
    public void onDrawerOpened(View arg0) {

    }

    @Override
    public void onDrawerSlide(View arg0, float slideOffset) {
        float translationX = getTranslation(slideOffset);
        mHandle.setTranslationX(translationX);
    }

    @Override
    public void onDrawerStateChanged(int arg0) {

    }

    public View getView(){
        return mHandle;
    }

    public View getDrawer() {
        return mDrawer;
    }

    public void setVerticalOffset(float offset) {
        updateScreenDimensions();
        mVerticalOffset = offset;
        mHandle.setY(mVerticalOffset*mScreenDimensions.y);
    }
}

Still i am not able to get the desired output ::

What i have done so far ::

MainActivity ::

import java.util.Locale;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.SearchManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;


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

    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    private String[] mPlanetTitles;

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

        mTitle = mDrawerTitle = getTitle();
        mPlanetTitles = getResources().getStringArray(R.array.planets_array);
        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.drawer_shadow,
                GravityCompat.START);
        // set up the drawer's list view with items and click listener
        mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                R.layout.drawer_list_item, mPlanetTitles));
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

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

        // 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) {
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to
                                            // onPrepareOptionsMenu()
            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to
                                            // onPrepareOptionsMenu()
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);
        float verticalOffset = 0.2f;
        View drawer = findViewById(R.id.content_frame);
        DrawerHandle.attach(drawer, R.layout.handle, verticalOffset);
        if (savedInstanceState == null) {
            selectItem(0);
        }

        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    /* The click listner for ListView in the navigation drawer */
    private class DrawerItemClickListener implements
            ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            selectItem(position);
        }
    }

    private void selectItem(int position) {
        // update the main content by replacing fragments
        Fragment fragment = new PlanetFragment();
        Bundle args = new Bundle();
        args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
        fragment.setArguments(args);

        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.content_frame, fragment).commit();

        // update selected item and title, then close the drawer
        mDrawerList.setItemChecked(position, true);
        setTitle(mPlanetTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    }
}

activity_main.xml

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

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#fff"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />

</android.support.v4.widget.DrawerLayout>

What i have got so far ::

enter image description here

now when i click on the drawer handle icon i got the following error...

Logcat ::

java.lang.IllegalArgumentException: View android.widget.FrameLayout{5282c560 V.E..... ........ 0,0-768,1038 #7f09003d app:id/content_frame} is not a drawer
at android.support.v4.widget.DrawerLayout.isDrawerOpen(DrawerLayout.java:1157)
at android.support.v4.widget.DrawerLayout.isDrawerOpen(DrawerLayout.java:1174)
at learn2crack.slidingnavigationdrawer.DrawerHandle$1.onClick(DrawerHandle.java:81)
at android.view.View.performClick(View.java:4438)
at learn2crack.slidingnavigationdrawer.DrawerHandle$2.onTouch(DrawerHandle.java:99)

Kindly let me know your valuable suggestion.

Any link/guideance will be helpful....

Thanks in advance ...

Euboea answered 28/1, 2015 at 6:58 Comment(1)
hope it will help #20289895Nankeen
A
1

You need to put you Drawer and and other UI code inside a DrawerLayout. Consider this example:

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

    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <com.fscz.views.BounceViewPager
            android:id="@+id/content_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" 
            android:layout_centerInParent="true"
            />

        <com.fscz.views.CirclePageIndicator
            android:id="@+id/content_indicator"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content" 
            android:padding="10dp"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            android:layout_marginTop="100dp"
            style="@style/link"
            />

    </RelativeLayout>

<LinearLayout
        android:id="@+id/drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="right"
        android:orientation="vertical"
        android:padding="20dp"
        android:background="@color/black_transparent"
        >
        <TextView
            android:layout_width="240dp"
            android:layout_height="wrap_content"
            style="@style/text"
            android:text="@string/collections"
            android:paddingBottom="20dp"
            />
        <ListView 
            android:id="@+id/drawer_list"
            android:layout_width="240dp"
            android:layout_height="0dip"
            android:choiceMode="singleChoice"
            android:divider="@android:color/transparent"
            android:dividerHeight="0dp"
            android:layout_weight="1"
            />
</LinearLayout>

</android.support.v4.widget.DrawerLayout>

The root element is an android.support.v4.widget.DrawerLayout. Inside there are 2 elements. A RelativeLayout and a LinearLayout. By convention the DrawerLayout assumes, that the first element is the actual layout of your activity/fragment/whatever. The second element is the drawer. Not the drawer handle but the UI you drag in from the side. You add the handle via Java code.

So.. in a nutshell. You try to add the the handle to the layout - in my case a RelativeLayout, in your case a FrameLayout - and not to the drawer. In your example the drawer has the id: left_drawer

Affirm answered 29/1, 2015 at 10:41 Comment(0)
S
-1

Try this in onClick in DrawerHandle class

if (mDrawerlayout.isDrawerOpen(Gravity.START)) {
                    mDrawerlayout.closeDrawers();
                } else {
                    mDrawerlayout.openDrawer(Gravity.START);
                }
Sigismondo answered 29/1, 2015 at 10:56 Comment(2)
has nothing to do with it. he's trying to add the handle to the layout and not the drawerAffirm
This all was supposed to that handle click listener dude better check before rejecting answer .Sigismondo

© 2022 - 2024 — McMap. All rights reserved.