Fragment Navigation Drawer如何从右向左打开?

时间:2016-09-14 00:26:29

标签: android android-fragments navigation-drawer android-navigation-drawer

我是android的初学者并实现我的第一个应用程序! 我在我的应用程序中使用片段导航抽屉,我希望它从右到左打开。在主xml文件的fragment标签中,我设置了android:layout_gravity="right",但是当我运行我的应用程序并触摸切换按钮打开导航抽屉时,应用程序突然崩溃了!我从logcat收到java.lang.IllegalArgumentException: No drawer view found with gravity LEFT的错误。我该怎么做才能解决这个问题? 非常感谢。

// NavDrawerItem.java

public class NavDrawerItem {
    private boolean showNotify;
    private String title;    

    public NavDrawerItem() {    
    }

    public NavDrawerItem(boolean showNotify, String title) {
        this.showNotify = showNotify;
        this.title = title;
    }

    public boolean isShowNotify() {
        return showNotify;
    }

    public void setShowNotify(boolean showNotify) {
        this.showNotify = showNotify;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

nav_drawer_row.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true">

    <TextView
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="30dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:textSize="15dp"
        android:textStyle="bold" />

</RelativeLayout>

fragment_navigation_drawer.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layoutDirection="rtl"
    android:background="@android:color/white">    

    <RelativeLayout
        android:id="@+id/nav_header_container"
        android:layout_width="match_parent"
        android:layout_height="140dp"
        android:layout_alignParentTop="true"
        android:background="@color/colorPrimary">

        <ImageView
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:src="@drawable/ic_user"
            android:scaleType="fitCenter"
            android:layout_centerInParent="true" />

    </RelativeLayout>    

    <android.support.v7.widget.RecyclerView        
        android:layout_marginRight="15dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/nav_header_container"

        android:layout_marginTop="15dp" />

</RelativeLayout>

NavigationDrawerAdapter.java:

public class NavigationDrawerAdapter extends RecyclerView.Adapter<NavigationDrawerAdapter.MyViewHolder> {
    List<NavDrawerItem> data = Collections.emptyList();
    private LayoutInflater inflater;
    private Context context;

    public NavigationDrawerAdapter(Context context, List<NavDrawerItem> data) {
        this.context = context;
        inflater = LayoutInflater.from(context);
        this.data = data;
    }

    public void delete(int position) {
        data.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.nav_drawer_row, parent, false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        NavDrawerItem current = data.get(position);
        holder.title.setText(current.getTitle());
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        TextView title;

        public MyViewHolder(View itemView) {
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.title);
        }
    }
}

FragmentDrawer.java:

public class FragmentDrawer extends Fragment {

    private static String TAG = FragmentDrawer.class.getSimpleName();

    private RecyclerView recyclerView;
    private ActionBarDrawerToggle mDrawerToggle;
    private DrawerLayout mDrawerLayout;
    private NavigationDrawerAdapter adapter;
    private View containerView;
    private static String[] titles = null;
    private FragmentDrawerListener drawerListener;

    public FragmentDrawer() {    
    }

    public void setDrawerListener(FragmentDrawerListener listener) {
        this.drawerListener = listener;
    }

    public static List<NavDrawerItem> getData() {
        List<NavDrawerItem> data = new ArrayList<>();    

        // preparing navigation drawer items
        for (int i = 0; i < titles.length; i++) {
            NavDrawerItem navItem = new NavDrawerItem();
            navItem.setTitle(titles[i]);
            data.add(navItem);
        }
        return data;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // drawer labels
        titles = getActivity().getResources().getStringArray(R.array.nav_drawer_labels);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflating view layout
        View layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
        recyclerView = (RecyclerView) layout.findViewById(R.id.drawerList);

        adapter = new NavigationDrawerAdapter(getActivity(), getData());
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
            @Override
            public void onClick(View view, int position) {
                drawerListener.onDrawerItemSelected(view, position);
                mDrawerLayout.closeDrawer(containerView);
            }

            @Override
            public void onLongClick(View view, int position) {

            }
        }));

        return layout;
    }


    public void setUp(int fragmentId, DrawerLayout drawerLayout, final Toolbar toolbar) {
        containerView = getActivity().findViewById(fragmentId);
        mDrawerLayout = drawerLayout;
        mDrawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActivity().invalidateOptionsMenu();
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                getActivity().invalidateOptionsMenu();
            }

            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                super.onDrawerSlide(drawerView, slideOffset);
                toolbar.setAlpha(1 - slideOffset / 2);
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);
        mDrawerLayout.post(new Runnable() {
            @Override
            public void run() {
                mDrawerToggle.syncState();
            }
        });    
    }

    public static interface ClickListener {
        public void onClick(View view, int position);

        public void onLongClick(View view, int position);
    }

    static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {

        private GestureDetector gestureDetector;
        private ClickListener clickListener;

        public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
            this.clickListener = clickListener;
            gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onSingleTapUp(MotionEvent e) {
                    return true;
                }

                @Override
                public void onLongPress(MotionEvent e) {
                    View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                    if (child != null && clickListener != null) {
                        clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                    }
                }
            });
        }

        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {

            View child = rv.findChildViewUnder(e.getX(), e.getY());
            if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
                clickListener.onClick(child, rv.getChildPosition(child));
            }
            return false;
        }

        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {    
        }   
    }

    public interface FragmentDrawerListener {
        public void onDrawerItemSelected(View view, int position);
   }
}

activity_main.xml中:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/container_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <include
                android:id="@+id/toolbar"
                layout="@layout/toolbar" />
        </LinearLayout>

        <FrameLayout
            android:id="@+id/container_body"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />    

    </LinearLayout>   

    <fragment
        android:id="@+id/fragment_navigation_drawer"
        android:name="com.example.videolabpc.mytoolbar.FragmentDrawer"
        android:layout_width="@dimen/nav_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:layout="@layout/fragment_navigation_drawer"
        tools:layout="@layout/fragment_navigation_drawer" />

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

MainActivity.java:

private FragmentDrawer drawerFragment;
drawerFragment = (FragmentDrawer)    getSupportFragmentManager().findFragmentById(R.id.fragment_navigation_drawer);
        drawerFragment.setUp(R.id.fragment_navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), mToolbar);
        drawerFragment.setDrawerListener(this);

崩溃后的Logcat:

09-14 04:24:46.193 1539-1539/? E/SensorManager: sensor or listener is null
09-14 04:24:46.194 1539-1539/? E/SensorManager: registerListenerImpl() [Sensor: null, SensorEventListener: com.lge.lockscreen.model.ScreenTurnOffBySensor@5997807] by com.lge.lockscreen.model.ScreenTurnOffBySensor.registerProximitySensor():58
09-14 04:24:46.203 278-2219/? E/lge_audio_pcm_dump: lge_set_dump_config: exit dump_config : 0
09-14 04:24:48.544 278-1070/? E/audio_hw_primary: select_devices: enter and usecase(1)
09-14 04:24:48.545 278-1070/? E/audio_hw_primary: enable_snd_device: enter  2
09-14 04:24:51.913 278-1325/? E/audio_hw_primary: disable_snd_device: enter 2
09-14 04:25:14.826 5149-5149/com.teroject.teroject E/GMPM: GoogleService failed to initialize, status: 10, Missing an expected resource: 'R.string.google_app_id' for initializing Google services.  Possible causes are missing google-services.json or com.google.gms.google-services gradle plugin.
09-14 04:25:14.826 5149-5149/com.teroject.teroject E/GMPM: Scheduler not set. Not logging error/warn.
09-14 04:25:14.881 5149-5181/com.teroject.teroject E/GMPM: Uploading is not possible. App measurement disabled
09-14 04:25:15.600 5149-5149/com.teroject.teroject E/OneSignal: You must initialize OneSignal before modifying tags! Omitting this tag operation.
09-14 04:25:16.658 272-994/? E/BandwidthController: [LG DATA] No such appUid: 10004
09-14 04:25:16.860 272-994/? E/BandwidthController: [LG DATA] No such appUid: 10187
09-14 04:25:16.901 5149-5149/com.teroject.teroject E/MediaProfilesEx-JNI: register_com_lge_media_MediaProfilesEx
09-14 04:25:16.903 5149-5149/com.teroject.teroject E/MediaRecorderEx-JNI: register_com_lge_media_MediaRecorderEx
09-14 04:25:16.905 5149-5149/com.teroject.teroject E/SurfaceControlEx: register_com_lge_view_SurfaceControlEx
09-14 04:25:16.912 5149-5149/com.teroject.teroject E/MediaPlayerEx-jni: register_com_lge_view_MediaPlayerEx
09-14 04:25:21.548 5149-5149/com.teroject.teroject E/AndroidRuntime: FATAL EXCEPTION: main
                                                                     Process: com.teroject.teroject, PID: 5149
                                                                     java.lang.IllegalArgumentException: No drawer view found with gravity LEFT
                                                                         at android.support.v4.widget.DrawerLayout.openDrawer(DrawerLayout.java:1618)
                                                                         at android.support.v7.app.ActionBarDrawerToggle.toggle(ActionBarDrawerToggle.java:290)
                                                                         at android.support.v7.app.ActionBarDrawerToggle.access$100(ActionBarDrawerToggle.java:64)
                                                                         at android.support.v7.app.ActionBarDrawerToggle$1.onClick(ActionBarDrawerToggle.java:200)
                                                                         at android.view.View.performClick(View.java:4764)
                                                                         at android.view.View$PerformClick.run(View.java:19844)
                                                                         at android.os.Handler.handleCallback(Handler.java:739)
                                                                         at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                         at android.os.Looper.loop(Looper.java:135)
                                                                         at android.app.ActivityThread.main(ActivityThread.java:5354)
                                                                         at java.lang.reflect.Method.invoke(Native Method)
                                                                         at java.lang.reflect.Method.invoke(Method.java:372)
                                                                         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
                                                                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
09-14 04:25:21.579 278-1070/? E/audio_hw_primary: select_devices: enter and usecase(1)
09-14 04:25:21.579 278-1070/? E/audio_hw_primary: enable_snd_device: enter  2
09-14 04:25:21.766 1001-1483/? E/ConnectivityService: RemoteException caught trying to send a callback msg for NetworkRequest [ id=8, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN] ]
09-14 04:25:22.510 2648-2648/? E/NetworkScheduler.SR: Invalid parameter app
09-14 04:25:22.510 2648-2648/? E/NetworkScheduler.SR: Invalid package name : Perhaps you didn't include a PendingIntent in the extras?
09-14 04:25:22.562 3927-4157/? E/Drive.UninstallOperation: Package still installed com.teroject.teroject
09-14 04:25:22.730 5547-5547/? E/Finsky: [1] com.google.android.finsky.wear.bo.a(838): onConnectionFailed: ConnectionResult{statusCode=API_UNAVAILABLE, resolution=null, message=null}
09-14 04:25:23.217 3927-5659/? E/IntentOperationSvc: Failed to instantiate Chimera operation impl, dropping operation
09-14 04:25:23.223 5547-5547/? E/Finsky: [1] com.google.android.finsky.wear.bo.a(838): onConnectionFailed: ConnectionResult{statusCode=API_UNAVAILABLE, resolution=null, message=null}
09-14 04:25:24.332 272-994/? E/BandwidthController: [LG DATA] No such appUid: 10187
09-14 04:25:24.585 2648-2648/? E/NetworkScheduler.SR: Invalid parameter app
09-14 04:25:24.585 2648-2648/? E/NetworkScheduler.SR: Invalid package name : Perhaps you didn't include a PendingIntent in the extras?
09-14 04:25:24.776 278-1325/? E/audio_hw_primary: disable_snd_device: enter 2
09-14 04:25:24.799 5860-5860/? E/App: [App][onCreate()] 4.40.21
09-14 04:25:26.507 272-994/? E/BandwidthController: [LG DATA] No such appUid: 10101
09-14 04:25:27.341 272-994/? E/BandwidthController: [LG DATA] No such appUid: 10100
09-14 04:25:29.554 5901-5936/? E/a: Failed to send crash attachment report /data/data/com.instagram.android/app_minidumps/307ff5ad80207d193ff0aa19e8633a8a.dmp
                                    com.facebook.g.b.c: Error while sending report to Http Post Form.
                                        at com.facebook.g.b.d.a(HttpPostSender.java:110)
                                        at com.facebook.g.n.b(ErrorReporter.java:1436)
                                        at com.facebook.g.n.a(ErrorReporter.java:1626)
                                        at com.facebook.g.n.a(ErrorReporter.java:1483)
                                        at com.facebook.g.n.a(ErrorReporter.java:118)
                                        at com.facebook.g.i.a(ErrorReporter.java:348)
                                        at com.facebook.g.i.run(ErrorReporter.java:360)
                                     Caused by: java.net.SocketTimeoutException: failed to connect to www.facebook.com/10.10.34.36 (port 443) after 3000ms
                                        at libcore.io.IoBridge.connectErrno(IoBridge.java:169)
                                        at libcore.io.IoBridge.connect(IoBridge.java:122)
                                        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:183)
                                        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:456)
                                        at java.net.Socket.connect(Socket.java:886)
                                        at com.android.okhttp.internal.Platform.connectSocket(Platform.java:139)
                                        at com.android.okhttp.Connection.connect(Connection.java:155)
                                        at com.android.okhttp.Connection.connect(Connection.java:170)
                                        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:309)
                                        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:242)
                                        at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:397)
                                        at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:118)
                                        at com.android.okhttp.internal.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:229)
                                        at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
                                        at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:25)
                                        at com.facebook.g.c.f.a(HttpRequest.java:52)
                                        at com.facebook.g.b.d.b(HttpPostSender.java:134)
                                        at com.facebook.g.b.d.a(HttpPostSender.java:108)
                                        at com.facebook.g.n.b(ErrorReporter.java:1436) 
                                        at com.facebook.g.n.a(ErrorReporter.java:1626) 
                                        at com.facebook.g.n.a(ErrorReporter.java:1483) 
                                        at com.facebook.g.n.a(ErrorReporter.java:118) 
                                        at com.facebook.g.i.a(ErrorReporter.java:348) 
                                        at com.facebook.g.i.run(ErrorReporter.java:360) 
09-14 04:25:32.298 5901-5901/? E/ActivityThread: Failed to find provider info for com.facebook.katana.provider.AttributionIdProvider
09-14 04:25:32.311 5901-5954/? E/ActivityThread: Failed to find provider info for com.facebook.katana.provider.AttributionIdProvider
09-14 04:25:32.446 272-994/? E/BandwidthController: [LG DATA] No such appUid: 10101
09-14 04:25:32.727 272-994/? E/BandwidthController: [LG DATA] No such appUid: 10101

2 个答案:

答案 0 :(得分:1)

问题是ActionBarDrawerToggle总是希望抽屉位于与Gravity.START对应的一侧。在大多数区域设置中,这是在左侧,因此它尝试使用Gravity.LEFT打开抽屉,但是您的是在另一侧,因此它会抛出异常。无论这看起来像是一个聪明的设计决定,它就是它的本质。

如果您遵循材料设计准则,您的抽屉将在操作栏打开时覆盖它(可能已经在执行此操作)。特别是出于这个原因,我不喜欢使用ActionBarDrawerToggle并且没有发现它特别有用;菜单图标到箭头的动画被抽屉遮挡,其他功能很容易直接在活动中实现。在您的情况下,如果您的另一侧的抽屉没有覆盖图标,动画可能实际上很有用,但是您可能根本不想让图标完全动画。

onCreate()方法中,您需要做的只是

  1. 致电toolbar.setNavigationOnClickListener()(或在OnClickListener的视图上设置Toolbar)并让此听众使用drawerLayout.openDrawer(Gravity.RIGHT)和等效的closeDrawer()切换抽屉方法
  2. 使用drawerLayout.addDrawerListener()添加侦听器。当抽屉打开或关闭时,您可以使用此监听器来更改工具栏的图标和/或其内容描述(用于辅助功能),或者做任何您喜欢的事情

答案 1 :(得分:0)

我添加以下属性:

android:layoutDirection="rtl"

到DrawerLayout和NavigationView解决了问题