当前位置: 首页 > 知识库问答 >
问题:

Android导航抽屉向右切换图标

楮自珍
2023-03-14

我的要求如下图所示,我的导航抽屉应该从右侧打开。我已经实现了这一点。我的导航抽屉从右向左打开。但问题是切换图标总是在左侧。如何将切换图标设置在右侧?

我查过以下SO问题,但没有一个有用:

将导航抽屉中的切换按钮图像图标从右改为左

<?xml version="1.0" encoding="utf-8"?>
<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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="end">

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context="com.example.nav.MainActivity"
        android:foregroundGravity="right">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="end"
            android:theme="@style/AppTheme.AppBarOverlay">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                android:layout_gravity="right"
                app:popupTheme="@style/AppTheme.PopupOverlay"
                android:foregroundGravity="right"
                android:textAlignment="viewEnd"
                android:touchscreenBlocksFocus="false" />

        </android.support.design.widget.AppBarLayout>

        <include layout="@layout/content_main" />

    </android.support.design.widget.CoordinatorLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="end"
        app:headerLayout="@layout/nav_header"
        app:menu="@menu/menu_navigation"
        android:textAlignment="viewEnd" />


</android.support.v4.widget.DrawerLayout>
public class MainActivity extends AppCompatActivity {
    private DrawerLayout drawerLayout;
    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        initNavigationDrawer();

    }

    @TargetApi(Build.VERSION_CODES.M)
    public void initNavigationDrawer() {

        NavigationView navigationView = (NavigationView)findViewById(R.id.navigation_view);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {

                int id = menuItem.getItemId();

                switch (id){
                    case R.id.home:
                        Toast.makeText(getApplicationContext(),"Home",Toast.LENGTH_SHORT).show();
                        drawerLayout.closeDrawers();
                        break;
                    case R.id.settings:
                        Toast.makeText(getApplicationContext(),"Settings",Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.trash:
                        Toast.makeText(getApplicationContext(),"Trash",Toast.LENGTH_SHORT).show();
                        drawerLayout.closeDrawers();
                        break;
                    case R.id.logout:
                        finish();

                }
                return true;
            }
        });
        drawerLayout = (DrawerLayout)findViewById(R.id.drawer);

        ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.drawer_open,R.string.drawer_close){

            @Override
            public void onDrawerClosed(View v){
                super.onDrawerClosed(v);
            }

            @Override
            public void onDrawerOpened(View v) {
                super.onDrawerOpened(v);
            }

            @Override
            public boolean onOptionsItemSelected(MenuItem item) {
                if (item != null && item.getItemId() == android.R.id.home) {
                    if (drawerLayout.isDrawerOpen(Gravity.RIGHT)) {
                        drawerLayout.closeDrawer(Gravity.RIGHT);
                    }
                    else {
                        drawerLayout.openDrawer(Gravity.RIGHT);
                    }
                }
                return false;
            }
        };
        drawerLayout.addDrawerListener(actionBarDrawerToggle);
        actionBarDrawerToggle.syncState();

        toolbar.setNavigationOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (drawerLayout.isDrawerOpen(Gravity.RIGHT)) {
                    drawerLayout.closeDrawer(Gravity.RIGHT);
                } else {
                    drawerLayout.openDrawer(Gravity.RIGHT);
                }
            }
        });
    }

}

共有1个答案

南门茂才
2023-03-14

实际上没有(实用的)方法让ActionBarDrawerToggle做到这一点,因为它总是设置在Start/left-side导航按钮上。但是,该类基本上只是一个DrawerListener,它管理一个专用的Drawable,并将一个ImageButton连接到DrawerLayout。我们可以将类似的东西放在结尾/右侧抽屉中,并将其与ImageButton放在Toolbar的同一侧(这是本例所必需的)。

public class EndDrawerToggle implements DrawerLayout.DrawerListener {

    private final DrawerLayout drawerLayout;
    private final AppCompatImageButton toggleButton;
    private final int openDrawerContentDescRes;
    private final int closeDrawerContentDescRes;

    private DrawerArrowDrawable arrowDrawable;

    public EndDrawerToggle(DrawerLayout drawerLayout, Toolbar toolbar,
                           int openDrawerContentDescRes, int closeDrawerContentDescRes) {
        this.drawerLayout = drawerLayout;
        this.openDrawerContentDescRes = openDrawerContentDescRes;
        this.closeDrawerContentDescRes = closeDrawerContentDescRes;

        toggleButton = new AppCompatImageButton(toolbar.getContext(), null,
                R.attr.toolbarNavigationButtonStyle);
        toolbar.addView(toggleButton, new Toolbar.LayoutParams(GravityCompat.END));
        toggleButton.setOnClickListener(v -> toggle());

        loadDrawerArrowDrawable();
    }

    public void syncState() {
        if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
            setPosition(1f);
        } else {
            setPosition(0f);
        }
    }

    public void onConfigurationChanged(Configuration newConfig) {
        loadDrawerArrowDrawable();
        syncState();
    }

    @Override
    public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
        setPosition(Math.min(1f, Math.max(0f, slideOffset)));
    }

    @Override
    public void onDrawerOpened(@NonNull View drawerView) {
        setPosition(1f);
    }

    @Override
    public void onDrawerClosed(@NonNull View drawerView) {
        setPosition(0f);
    }

    @Override
    public void onDrawerStateChanged(int newState) {}

    private void loadDrawerArrowDrawable() {
        arrowDrawable = new DrawerArrowDrawable(toggleButton.getContext());
        arrowDrawable.setDirection(DrawerArrowDrawable.ARROW_DIRECTION_END);
        toggleButton.setImageDrawable(arrowDrawable);
    }

    private void toggle() {
        final int drawerLockMode = drawerLayout.getDrawerLockMode(GravityCompat.END);
        if (drawerLayout.isDrawerVisible(GravityCompat.END)
                && (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
            drawerLayout.closeDrawer(GravityCompat.END);
        } else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
            drawerLayout.openDrawer(GravityCompat.END);
        }
    }

    private void setPosition(float position) {
        if (position == 1f) {
            arrowDrawable.setVerticalMirror(true);
            setContentDescription(closeDrawerContentDescRes);
        } else if (position == 0f) {
            arrowDrawable.setVerticalMirror(false);
            setContentDescription(openDrawerContentDescRes);
        }
        arrowDrawable.setProgress(position);
    }

    private void setContentDescription(int resId) {
        toggleButton.setContentDescription(toggleButton.getContext().getText(resId));
    }
}

EndDrawerToggle类的工作方式与ActionBarDrawerToggleToolbar一起使用时的工作方式完全相同(只是构造函数调用不需要Activity参数):首先实例化切换,然后将其添加为DrawerListener,并在ActivityOnPostCreate()方法中同步。如果您已经重写了activityonConfigurationChanged()方法,您将希望在那里调用切换的相应方法,就像您对ActionBardrawerToggle所做的那样。

private EndDrawerToggle drawerToggle;

public void initNavigationDrawer() {
    ...

    drawerLayout = (DrawerLayout) findViewById(R.id.drawer);

    drawerToggle = new EndDrawerToggle(drawerLayout,
                                       toolbar,
                                       R.string.drawer_open,
                                       R.string.drawer_close);

    drawerLayout.addDrawerListener(drawerToggle);
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    drawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    drawerToggle.onConfigurationChanged(newConfig);
}

如果您有两个抽屉,并且需要同时使用ActionBarDrawerToggleEndDrawerToggle,那么这是可能的,但是我们需要处理截取抽屉运动事件并将其调度到正确的切换。

如果您喜欢较少的类,可以将ActionBarDrawerToggle子类化,并将EndDrawerToggle的功能合并到其中,将每个DrawerListener方法调用分派到Super类或本地结束切换代码

然而,这里的composition可以说要干净得多,它将允许我们原样使用enddrawertoggle。此示例是一个DrawerListener,它将SyncState()OnConfigurationChanged()调用中继到每个切换,但只将侦听器方法调用分派到相应的一个,具体取决于正在移动的抽屉。

public class DualDrawerToggle implements DrawerLayout.DrawerListener {

    private final DrawerLayout drawerLayout;
    private final Toolbar toolbar;
    private final ActionBarDrawerToggle actionBarDrawerToggle;
    private final EndDrawerToggle endDrawerToggle;

    public DualDrawerToggle(Activity activity, DrawerLayout drawerLayout, Toolbar toolbar,
                            int startDrawerOpenContDescRes, int startDrawerCloseContDescRes,
                            int endDrawerOpenContDescRes, int endDrawerCloseContDescRes) {
        this.drawerLayout = drawerLayout;
        this.toolbar = toolbar;
        this.actionBarDrawerToggle =
                new ActionBarDrawerToggle(activity, drawerLayout, toolbar,
                        startDrawerOpenContDescRes, startDrawerCloseContDescRes);
        this.endDrawerToggle =
                new EndDrawerToggle(drawerLayout, toolbar,
                        endDrawerOpenContDescRes, endDrawerCloseContDescRes);
    }

    public void syncState() {
        actionBarDrawerToggle.syncState();
        endDrawerToggle.syncState();
    }

    public void onConfigurationChanged(Configuration newConfig) {
        actionBarDrawerToggle.onConfigurationChanged(newConfig);
        // Fixes bug in ABDT, which only reloads the up nav indicator, for some reason.
        final DrawerArrowDrawable dad = new DrawerArrowDrawable(toolbar.getContext());
        actionBarDrawerToggle.setDrawerArrowDrawable(dad);

        endDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
        if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
            actionBarDrawerToggle.onDrawerSlide(drawerView, slideOffset);
        } else {
            endDrawerToggle.onDrawerSlide(drawerView, slideOffset);
        }
    }

    @Override
    public void onDrawerOpened(@NonNull View drawerView) {
        if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
            actionBarDrawerToggle.onDrawerOpened(drawerView);
        } else {
            endDrawerToggle.onDrawerOpened(drawerView);
        }
    }

    @Override
    public void onDrawerClosed(@NonNull View drawerView) {
        if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
            actionBarDrawerToggle.onDrawerClosed(drawerView);
        } else {
            endDrawerToggle.onDrawerClosed(drawerView);
        }
    }

    @Override
    public void onDrawerStateChanged(int newState) {}

    @SuppressLint("RtlHardcoded")
    static boolean isStartDrawerView(View drawerView, int layoutDirection) {
        final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
        final int horizontalGravity = gravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK;
        if ((horizontalGravity & GravityCompat.RELATIVE_LAYOUT_DIRECTION) > 0) {
            return horizontalGravity == GravityCompat.START;
        } else {
            if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                return horizontalGravity == Gravity.RIGHT;
            } else {
                return horizontalGravity == Gravity.LEFT;
            }
        }
    }
}

同样,dualdrawertoggletoolbar一起使用时的工作方式与actionbardrawertoggle完全相同,只是构造函数中有额外的内容描述资源ID。

请注意,一个dualdrawertoggle在内部创建和管理两个其他切换。您不需要在活动中设置任何其他切换实例;只有dualdrawertoggle

备注:

这里使用的AppCompatimageButtonToolbar的常规子级。如果您正在使用工具栏上的菜单,该菜单将在布局中优先,并向内推切换。要将其保持在外部,您可以按照上面所述修改类,以设置操作菜单项上的切换。我在这里的回答中有一个例子。

如果您的设计要求您使用装饰提供的操作栏来代替您自己的工具栏,那么该菜单项示例也可能很有用。虽然ActionBarDrawerToggle可以与装饰提供的ActionBar一起工作,但本例无法正常工作。

 类似资料:
  • 我已经设置了一个左右两侧的导航抽屉。除了一件事,一切都很好。 我希望我的另一个动作栏项目切换右边的抽屉菜单。正常的左边动作栏切换效果很好。谷歌Android应用程序通知面板是我希望动作模仿的。 下面是我用来设置右侧切换的代码(现在它在单击时强制关闭): 如果有人知道怎么做,如果你能让我知道就太好了! 谢谢

  • 我想在ActionBar的右侧[而不是默认的左侧]显示ActionBar导航图标。 此外,我需要有相同的幻灯片在动画导航抽屉图标在Gmail和谷歌加应用程序。 有没有什么方法可以轻松实现右侧的动画。 任何形式的帮助或建议都是感激的。 提前道谢!

  • 有人能告诉我如何创建活动到这个主要活动,导航抽屉将看到在所有他们?我需要使用这个特定的MainActivity代码。我不需要使用碎片,只要3个简单的活动将添加到这个抽屉。 NavDrawer布局:

  • 我希望能够使用导航抽屉,并根据导航中的选择在不同片段之间进行更改。 我正在使用Android Studio,基本上我所做的是这样的: 使用内置模板“导航抽屉活动”创建了一个新项目 创建了一个空白片段 然后我更改了onNavigationDrawerItemSelected方法中的一些代码。 我的程序崩溃了,给了我很多我不理解的错误。我做错了什么?

  • 我知道如何改变抽屉图标,如果它在左侧,但我没有找到任何解决方案,改变导航抽屉汉堡图标,如果抽屉是在右侧。任何帮助都是可以感激的。

  • 我正在为我的应用程序实现一个导航抽屉。现在,除了一个小故障外,它工作正常。当我设置导航抽屉图标(ic_Drawer)来替换常规的“HomeAsUp”插入符号图标时,我仍然得到箭头。导航抽屉图标不显示。我已经实现了android开发者网站上的每一种方法。但它似乎不起作用。 以下是我的代码: