我的应用程序有两个活动,一个DrawerLayout
和一个NavigationView
(android.support.design.widget.NavigationView)。
我使用带有 parent 的应用程序主题Theme.AppCompat.Light.DarkActionBar
,对于我的 Lollipop 模拟器,没有问题。
但是对于我的 Jellybean 设备和模拟器,我有一个非常奇怪的行为:
项目的背景NavigationView
有时呈现为浅灰色(这对我来说没问题),有时呈现为浅蓝色阴影(我认为这是 Theme Holo 的默认设置)。
对于我的“真实”应用程序,灰色总是出现在第一个抽屉上,而蓝色总是出现在另一个抽屉上。起初我认为差异可能是由于一些细节,比如第一个使用 anActionBarDrawerToggle
而另一个没有,所以也许我不得不以某种方式android:listSelector
只为第二个设置。
所以我创建了一个类似 MCVE 的示例,并注意到两个抽屉不时显示两种颜色。这是一个错误还是我错过了什么?
我该怎么做才能摆脱 Theme Holo?
截图:
顺便说一句,我对ActionButton
背景有相同的随机行为:
我的代码(大约 95% 的代码适用于那些喜欢运行自己的测试的人):
activity_main.xml只是一个“空白活动”,中间有一个大的“Hello World”:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<TextView
android:text="@string/hello_world"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
activity_main_decor.xml
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"/>
<android.support.design.widget.NavigationView
android:id="@+id/main_drawer"
android:layout_width="@dimen/nav_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/menu_main_drawer"/>
</android.support.v4.widget.DrawerLayout>
activity_other.xml
<merge>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="Hello again!"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
</merge>
activity_other_decor.xml
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="@+id/container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include layout="@layout/activity_other"/>
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/other_drawer"
android:layout_width="@dimen/nav_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="end"
app:menu="@menu/menu_other_drawer" />
</android.support.v4.widget.DrawerLayout>
MainActivity - 导航抽屉必须从左侧和上方出现ActionBar
(顺便感谢@Peter Cai 提供了一些非常有用的行)
public class MainActivity extends AppCompatActivity
{
private static final String TAG = "StyleForDrawers main";
private static final String DRAWER_OPEN = "main_drawer_open";
private DrawerLayout drawerLayout;
private NavigationView navigationView;
private ActionBarDrawerToggle drawerToggle;
private boolean isDrawerOpen;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initNavDrawer();
}
private void initNavDrawer()
{
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(this);
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
drawerLayout = (DrawerLayout) inflater.inflate(R.layout.activity_main_decor, null);
ViewGroup decor = (ViewGroup)activity.getWindow().getDecorView();
View child = decor.getChildAt(0);
decor.removeView(child);
FrameLayout container = (FrameLayout)drawerLayout.findViewById(R.id.container);
container.addView(child);
decor.addView(drawerLayout);
navigationView = (NavigationView) findViewById(R.id.main_drawer);
navigationView.setItemTextColor(ContextCompat.getColorStateList(this, R.color.nav_item));
navigationView.setItemTextAppearance(R.style.MyNavdrawerTextAppearance);
View headerView = navigationView.inflateHeaderView(R.layout.navdrawer_list_header);
// header View should appear below status bar, so set padding:
(headerView.findViewById(R.id.nav_header_root)).setPadding(0, getStatusbarHeight(), 0, (int) getResources().getDimension(R.dimen.activity_vertical_margin));
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener()
{
@Override
public boolean onNavigationItemSelected(MenuItem menuItem)
{
Intent intent = null;
int id = menuItem.getItemId();
if (id == R.id.action_other_activity)
{
intent = new Intent(MainActivity.this, OtherActivity.class);
}
// -- skipped some code for Help etc. --
drawerLayout.closeDrawer(navigationView);
isDrawerOpen = false;
if (intent != null)
{
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
return true;
}
});
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.sDrawerOpen, R.string.sDrawerClose)
{
@Override
public void onDrawerClosed(View drawerView)
{
super.onDrawerClosed(drawerView);
sPrefs.edit().putBoolean(DRAWER_OPEN, false).apply();
}
@Override
public void onDrawerOpened(View drawerView)
{
isDrawerOpen = true;
super.onDrawerOpened(drawerView);
sPrefs.edit().putBoolean(DRAWER_OPEN, true).apply();
}
};
drawerLayout.setDrawerListener(drawerToggle);
if (getSupportActionBar() != null)
{
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.nav_drawer);
}
if (sPrefs.getBoolean(DRAWER_OPEN, true)) // open at first launch
{
drawerLayout.openDrawer(navigationView);
}
else
{
drawerLayout.closeDrawer(navigationView);
}
}
@Override
protected void onPause()
{
super.onPause();
SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(this);
sPrefs.edit().putBoolean(DRAWER_OPEN, isDrawerOpen).apply();
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
return drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
public static int getStatusbarHeight()
{
int retValue = 0;
int resID = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resID > 0) {
retValue = getResources().getDimensionPixelSize(resID);
}
return retValue;
}
}
OtherActivity - 抽屉就像一个上下文菜单,从右侧出现而不重叠ActionBar
:
public class OtherActivity extends AppCompatActivity
{
private static final String TAG = "StyleForDrawers other";
private static final String DRAWER_OPEN = "other_drawer_open";
private DrawerLayout mDrawerLayout;
private NavigationView mNavigationView;
private boolean mIsDrawerOpen;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other_decor);
initMenuDrawer();
}
private void initMenuDrawer()
{
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mNavigationView = (NavigationView) findViewById(R.id.other_drawer);
mNavigationView.setItemTextColor(ContextCompat.getColorStateList(this, R.color.nav_item));
mNavigationView.setItemTextAppearance(R.style.MyNavdrawerTextAppearance);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener()
{
@Override
public boolean onNavigationItemSelected(MenuItem menuItem)
{
int id = menuItem.getItemId();
if (id == R.id.action_back_to_main)
{
finish();
}
// -- skipped some code for doing something (else) --
mDrawerLayout.closeDrawer(mNavigationView);
mIsDrawerOpen = false;
return true;
}
});
mDrawerLayout.setDrawerListener(new DrawerLayout.SimpleDrawerListener()
{
@Override
public void onDrawerOpened(View drawerView)
{
super.onDrawerOpened(drawerView);
mIsDrawerOpen = true;
sPrefs.edit().putBoolean(DRAWER_OPEN, true).apply();
}
@Override
public void onDrawerClosed(View drawerView)
{
super.onDrawerClosed(drawerView);
mIsDrawerOpen = false;
sPrefs.edit().putBoolean(DRAWER_OPEN, false).apply();
}
});
if (sPrefs.getBoolean(DRAWER_OPEN, false)) // don't open at first launch
{
mDrawerLayout.openDrawer(mNavigationView);
}
else
{
mDrawerLayout.closeDrawer(mNavigationView);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.menu_other, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
int id = item.getItemId();
if (id == R.id.action_opendrawer)
{
if (mIsDrawerOpen)
{
mDrawerLayout.closeDrawer(mNavigationView);
}
else
{
mDrawerLayout.openDrawer(mNavigationView);
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
menu_main.xml不必要
menu_other.xml包含一个用于打开/关闭抽屉的操作按钮:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_opendrawer"
android:title="open/close drawer"
android:icon="@drawable/nav_drawer"
android:orderInCategory="100"
app:showAsAction="always"/>
</menu>
样式.xml
<resources>
<color name="accent_orange">#ff6d00</color>
<color name="my_background">#eeeeee</color>
<color name="my_text">#311b92</color>
<color name="my_sec_text">#B1311b92</color>
<color name="my_actionbar">#1a237e</color>
<color name="my_statusbar">#1a237e</color>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/my_actionbar</item>
<item name="colorPrimaryDark">@color/my_statusbar</item>
<item name="colorAccent">#ffc400</item>
<item name="android:windowBackground">@color/my_background</item>
<item name="android:textColorPrimary">@color/my_text</item>
<item name="android:textColor">@color/my_text</item>
<item name="android:textColorSecondary">@color/my_sec_text</item>
</style>
<style name="MyNavdrawerTextAppearance" parent="TextAppearance.AppCompat.Small">
<item name="android:textStyle">bold</item>
</style>
</resources>
更新(2016 年 5 月)
同时,我也尝试为这些NavigationView
项目设置自己的背景。背景发生了变化,但在触摸时,我仍然会得到 Lollipop 和更高版本的涟漪(没关系),不幸的是,Jellybean 上的交替效果仍然存在,可能来自某种我不知道如何操作的列表选择器。
更新 2(2016 年 9 月)
我安装了新版本的 Android Studio,正在使用最新版本的构建工具和所有库(分别为 24.0.2 和 24.2.0),甚至放弃ActionBar
了Toolbar
. 最后一点意味着我不必在 Main 中使用 hack 来让导航抽屉覆盖 . ActionBar
,因此我不再在代码中使用 LayoutInflater。
但仍然没有运气:(
我很确定这是一个错误:相同的代码从一个应用程序运行到下一个应用程序的行为不同,并且在同一次运行期间活动 Main和Other 之间的不一致。