滑出保持突出显示的导航项
Posted
技术标签:
【中文标题】滑出保持突出显示的导航项【英文标题】:Slide out navigation items staying highlighted 【发布时间】:2014-06-04 23:01:11 【问题描述】:在我的 android 应用程序中,我有一个滑出式导航抽屉。当在导航抽屉中选择一个项目时,它会加载新片段并突出显示您在导航抽屉中单击的项目。
我的问题是,在加载的新片段中,您可以单击该片段中的新项目,该项目会加载新片段并仍保留导航抽屉。
在这种情况下,您不再位于导航抽屉中列出的片段上,但最后一项仍突出显示,然后无法再次单击以返回。
关于如何在导航抽屉中取消突出显示不是我的主要片段之一的项目,然后在主要片段之一上重新突出显示的任何想法?
这是我的导航抽屉代码:
public class MainDrawer2 extends FragmentActivity
private static final String EXTRA_NAV_ITEM = "extraNavItem";
private static final String STATE_CURRENT_NAV = "stateCurrentNav";
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private NavDrawerListAdapter mDrawerAdapter;
private ListView mDrawerList;
private CharSequence mTitle;
private CharSequence mDrawerTitle;
private MainNavItem mCurrentNavItem;
public static Intent createLaunchFragmentIntent(Context context, MainNavItem navItem)
return new Intent(context, MainDrawer2.class)
.putExtra(EXTRA_NAV_ITEM, navItem.ordinal());
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
Crashlytics.start(this);
mTitle = mDrawerTitle = getTitle();
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
mDrawerList = (ListView)findViewById(R.id.drawer);
getActionBar().setDisplayHomeAsUpEnabled(true);
enableHomeButtonIfRequired();
mDrawerAdapter = new NavDrawerListAdapter(getApplicationContext());
mDrawerList.setAdapter(mDrawerAdapter);
mDrawerList.setOnItemClickListener(new ListView.OnItemClickListener()
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
displayNavFragment((MainNavItem)parent.getItemAtPosition(position));
);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.app_name, R.string.app_name)
public void onDrawerClosed(View view)
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
public void onDrawerOpened(View drawerView)
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu();
;
mDrawerLayout.setDrawerListener(mDrawerToggle);
if(getIntent().hasExtra(EXTRA_NAV_ITEM))
MainNavItem navItem = MainNavItem.values()
[getIntent().getIntExtra(EXTRA_NAV_ITEM,
MainNavItem.STATISTICS.ordinal())];
displayNavFragment(navItem);
else if(savedInstanceState != null)
mCurrentNavItem = MainNavItem.values()
[savedInstanceState.getInt(STATE_CURRENT_NAV)];
setCurrentNavItem(mCurrentNavItem);
else
displayNavFragment(MainNavItem.STATISTICS);
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void enableHomeButtonIfRequired()
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
getActionBar().setHomeButtonEnabled(true);
public void setActionBarTitle(String title)
getActionBar().setTitle(title);
@Override
public void setTitle(CharSequence title)
mTitle = title;
getActionBar().setTitle(mTitle);
@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 toggles
mDrawerToggle.onConfigurationChanged(newConfig);
@Override
protected void onSaveInstanceState(Bundle outState)
super.onSaveInstanceState(outState);
outState.putInt(STATE_CURRENT_NAV, mCurrentNavItem.ordinal());
@Override
public boolean onCreateOptionsMenu(Menu menu)
getMenuInflater().inflate(R.menu.main, menu);
return true;
/*
@Override
public boolean onPrepareOptionsMenu(Menu menu)
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
*/
private void displayNavFragment(MainNavItem navItem)
if(navItem == mCurrentNavItem)
return;
Fragment fragment = Fragment.instantiate(this,
navItem.getFragClass().getName());
if(fragment != null)
getSupportFragmentManager().beginTransaction()
.replace(R.id.main, fragment)
.commit();
setCurrentNavItem(navItem);
private void setCurrentNavItem(MainNavItem navItem)
int position = navItem.ordinal();
// If navItem is in DrawerAdapter
if(position >= 0 && position < mDrawerAdapter.getCount())
mDrawerList.setItemChecked(position, true);
else
// navItem not in DrawerAdapter, de-select current item
if(mCurrentNavItem != null)
mDrawerList.setItemChecked(mCurrentNavItem.ordinal(), false);
mDrawerLayout.closeDrawer(mDrawerList);
setTitle(navItem.getTitleResId());
mCurrentNavItem = navItem;
@Override
public boolean onOptionsItemSelected(MenuItem item)
switch (item.getItemId())
case android.R.id.home:
if(mDrawerLayout.isDrawerOpen(mDrawerList))
mDrawerLayout.closeDrawer(mDrawerList);
else
mDrawerLayout.openDrawer(mDrawerList);
return true;
default:
return super.onOptionsItemSelected(item);
public void goToSearch(MenuItem item)
//go to search page
Fragment Fragment_one;
FragmentManager man= getSupportFragmentManager();
FragmentTransaction tran = man.beginTransaction();
Fragment_one = new Search();
tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
tran.commit();
public void scanBarcode(MenuItem item)
//open scanner
IntentIntegrator scanIntegrator = new IntentIntegrator(this);
scanIntegrator.initiateScan();
public void onActivityResult(int requestCode, int resultCode, Intent intent)
//retrieve scan result
IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanningResult != null)
//we have a result
String scanContent = scanningResult.getContents();
//todo: set scan content into setting, load new fragment which calls async task below. New
//todo: fragment will have same ui as search. :-)
Fragment Fragment_one;
FragmentManager man= this.getSupportFragmentManager();
FragmentTransaction tran = man.beginTransaction();
Fragment_one = new BarcodeFrag(scanContent);
tran.replace(R.id.main, Fragment_one);//tran.
tran.addToBackStack(null);
//tran.commit();
tran.commitAllowingStateLoss();
else
Toast toast = Toast.makeText(getApplicationContext(),
"No scan data received!", Toast.LENGTH_SHORT);
toast.show();
然后我有一个名为 main nav item 的枚举:
public enum MainNavItem
// Displayed in NavDrawerListAdapter
STATISTICS("Your Statistics", R.layout.statistics_pagelayout, StatisticsTab.class),
DISCOVER ("Discover", R.layout.activity_discover, DiscoverTab.class),
PORTFOLIO ("Portfolio", R.layout.activity_portfolio, Portfolio.class),
LISTS ("Your Lists", R.layout.activity_search, AllLists.class),
NEWS ("News", R.layout.activity_news, NewsWeb.class),
Find ("Nearby Breweries", R.layout.beer_location_list, FindBrewery.class),
CONTACT ("Contact", R.layout.activity_contact, ContactPage.class),
// Items NOT displayed in NavDrawerListAdapter
SEARCH ("Search", R.layout.activity_search, Search.class),
;
private static MainNavItem LAST_NAV_ITEM = CONTACT;
private String mTitleResId;
private int mLayoutResId;
private Class<? extends Fragment> mFragClass;
private MainNavItem(String titleResId, int layoutResId, Class<? extends Fragment> fragClass)
mTitleResId = titleResId;
mLayoutResId = layoutResId;
mFragClass = fragClass;
public int getLayoutResId()
return mLayoutResId;
public String getTitleResId()
return mTitleResId;
public Class<? extends Fragment> getFragClass()
return mFragClass;
public static MainNavItem[] getNavAdapterItems()
int count = LAST_NAV_ITEM.ordinal() + 1;
MainNavItem[] adapterItems = new MainNavItem[count];
for(int i = 0; i < count; i++)
adapterItems[i] = values()[i];
return adapterItems;
更新:
我只是尝试注释掉这两行以关闭一般的突出显示,以便用户可以在我的导航抽屉中再次重新选择一个项目。
private void setCurrentNavItem(MainNavItem navItem)
int position = navItem.ordinal();
// If navItem is in DrawerAdapter
if(position >= 0 && position < mDrawerAdapter.getCount())
//mDrawerList.setItemChecked(position, true);
else
// navItem not in DrawerAdapter, de-select current item
if(mCurrentNavItem != null)
//mDrawerList.setItemChecked(mCurrentNavItem.ordinal(), false);
mDrawerLayout.closeDrawer(mDrawerList);
setTitle(navItem.getTitleResId());
mCurrentNavItem = navItem;
当应用程序第一次启动时,没有突出显示,但是当我单击某些内容时,它会突出显示并且我无法再次单击它来重新加载该片段。还有其他想法吗?
【问题讨论】:
【参考方案1】:我只是将我的项目分组如下,android:checkableBehavior="none" 这行非常重要,请确保它应该是 none。
<group android:checkableBehavior="none">
<item
android:id="@+id/nav_home"
android:icon="@drawable/left_menu_home"
android:title="@string/home" />
<item
android:id="@+id/nav_account_settings"
android:icon="@drawable/left_menu_account_settings"
android:title="@string/accountSettings" />
</group>
【讨论】:
【参考方案2】:想通了。不突出显示绘图中的项目的最简单方法是在绘图 linst 的 xml 中,choiceMode 应该是 none:
<FrameLayout
android:id="@+id/main"
android:layout_
android:layout_ >
</FrameLayout>
<ListView
android:id="@+id/drawer"
android:layout_
android:layout_
android:layout_gravity="start"
android:divider="@android:color/white"
android:background="@android:color/black"
android:choiceMode="none"/>
【讨论】:
或者根本不添加choiceMode?span> 【参考方案3】:您可以通过调用menuItem.setChecked(false);
取消选择导航抽屉菜单项
【讨论】:
【参考方案4】:关于如何在导航抽屉中取消突出显示不是我的主要片段之一的项目的任何想法
int toClear=mDrawerList.getCheckedItemPosition();
if (toClear >= 0)
mDrawerList.setItemChecked(toClear, false);
然后在主要片段之一上重新突出显示?
使用可见片段对应的位置调用setItemChecked()
,第二个参数调用true
。
This sample project 证明了这一点。我使用post()
来控制我们何时更新ListView
中的检查状态有点草率,但就足够了。
【讨论】:
我可以把这段代码放在我不想突出显示的片段中吗? int toClear=mDrawerList.getCheckedItemPosition(); if (toClear >= 0) mDrawerList.setItemChecked(toClear, false); @Mike:嗯,片段没有抽屉,所以它们没有mDrawerList
。而且我会争辩说,它们是否在抽屉中不是片段的决定,因为抽屉是一个活动关注点,而不是一个片段关注点。
那么我对上面的代码是如何工作的有点困惑。它如何知道何时不突出显示导航抽屉中的项目?
@Mike:因为活动是执行FragmentTransactions
来更改片段的活动,所以它知道更新导航抽屉以匹配。
好的,我在这里尝试了您的代码。在我进一步研究之后,这对我来说是有意义的。这确实使它在选择时保持突出显示,但是如果我转到另一个片段并在导航抽屉中选择相同的项目,它不会重新加载该片段并突出显示。以下是我实现您的代码的方式:gist.github.com/anonymous/bbf4c532a439fb908935以上是关于滑出保持突出显示的导航项的主要内容,如果未能解决你的问题,请参考以下文章