Creating a Navigation Drawer中使用的Navigation Drawer的android:minSdkVersion="14",现在Android API Version 小于14的还有30%左右呢。Android个版本的占有量可参考 Platform Version

Android Platform Version

我们的应用为了适配不同的版本,需要降低minSdkVersion,作者一般适配SDK到API 7。这一篇博文也是把Creating a Navigation Drawer的例子适配到API 7 。例子中降低API最主要的修改Action Bar,Action Bar是API 11才出现的,适配到API 7,我们使用了actionbarsherlock.

修改后的代码:

public class MainActivity extends SherlockFragmentActivity {
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
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().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 */
) { /** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
} /** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle(mDrawerTitle);
} };
mDrawerLayout.setDrawerListener(mDrawerToggle); if (savedInstanceState == null) {
selectItem(0);
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
} /* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
// if (mDrawerToggle.onOptionsItemSelected(item)) {
// return true;
// }
// Handle action buttons
switch(item.getItemId()) {
case android.R.id.home:
handleNavigationDrawerToggle();
return true;
case R.id.action_websearch:
// create intent to perform web search for this planet
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, getSupportActionBar().getTitle());
// catch event that there's no activity to handle intent
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void handleNavigationDrawerToggle() {
if (mDrawerLayout.isDrawerOpen(mDrawerList)) {
mDrawerLayout.closeDrawer(mDrawerList);
} else {
mDrawerLayout.openDrawer(mDrawerList);
}
}
/* 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 = getSupportFragmentManager();
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
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
} /**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/ @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);
} /**
* Fragment that appears in the "content_frame", shows a planet
*/
public static class PlanetFragment extends Fragment {
public static final String ARG_PLANET_NUMBER = "planet_number"; public PlanetFragment() {
// Empty constructor required for fragment subclasses
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_planet, container, false);
int i = getArguments().getInt(ARG_PLANET_NUMBER);
String planet = getResources().getStringArray(R.array.planets_array)[i]; int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()),
"drawable", getActivity().getPackageName());
((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId);
getActivity().setTitle(planet);
return rootView;
}
}
}

如果只修改JAVA代码,运行应用还是会出现异常:

08-13 13:26:15.909: E/AndroidRuntime(6832): FATAL EXCEPTION: main
08-13 13:26:15.909: E/AndroidRuntime(6832): android.view.InflateException: Binary XML file line #2: Error inflating class <unknown>
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.LayoutInflater.createView(LayoutInflater.java:518)
08-13 13:26:15.909: E/AndroidRuntime(6832): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:568)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.LayoutInflater.inflate(LayoutInflater.java:386)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:332)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.ArrayAdapter.getView(ArrayAdapter.java:323)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.AbsListView.obtainView(AbsListView.java:1495)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.ListView.measureHeightOfChildren(ListView.java:1216)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.ListView.onMeasure(ListView.java:1127)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.View.measure(View.java:8335)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.RelativeLayout.measureChild(RelativeLayout.java:566)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:381)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.View.measure(View.java:8335)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.FrameLayout.onMeasure(FrameLayout.java:250)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.View.measure(View.java:8335)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.LinearLayout.measureVertical(LinearLayout.java:531)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.LinearLayout.onMeasure(LinearLayout.java:309)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.View.measure(View.java:8335)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:3138)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.FrameLayout.onMeasure(FrameLayout.java:250)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.View.measure(View.java:8335)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.ViewRoot.performTraversals(ViewRoot.java:843)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.ViewRoot.handleMessage(ViewRoot.java:1892)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.os.Handler.dispatchMessage(Handler.java:99)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.os.Looper.loop(Looper.java:130)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.app.ActivityThread.main(ActivityThread.java:3835)
08-13 13:26:15.909: E/AndroidRuntime(6832): at java.lang.reflect.Method.invokeNative(Native Method)
08-13 13:26:15.909: E/AndroidRuntime(6832): at java.lang.reflect.Method.invoke(Method.java:507)
08-13 13:26:15.909: E/AndroidRuntime(6832): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
08-13 13:26:15.909: E/AndroidRuntime(6832): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
08-13 13:26:15.909: E/AndroidRuntime(6832): at dalvik.system.NativeStart.main(Native Method)
08-13 13:26:15.909: E/AndroidRuntime(6832): Caused by: java.lang.reflect.InvocationTargetException
08-13 13:26:15.909: E/AndroidRuntime(6832): at java.lang.reflect.Constructor.constructNative(Native Method)
08-13 13:26:15.909: E/AndroidRuntime(6832): at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.LayoutInflater.createView(LayoutInflater.java:505)
08-13 13:26:15.909: E/AndroidRuntime(6832): ... 32 more
08-13 13:26:15.909: E/AndroidRuntime(6832): Caused by: java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x2
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.content.res.TypedArray.getDimensionPixelSize(TypedArray.java:463)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.view.View.<init>(View.java:1978)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.TextView.<init>(TextView.java:350)
08-13 13:26:15.909: E/AndroidRuntime(6832): at android.widget.TextView.<init>(TextView.java:343)
08-13 13:26:15.909: E/AndroidRuntime(6832): ... 35 more

这个异常是
drawer_list_item.xml文件的内容产生的,drawer_list_item.xml内容:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColor="#fff"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeightSmall"/>

而在API 14之前的版本中,下面的三个属性会报异常:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeightSmall"/>

如果想适配更低的版本需要做如下的修改:

1)修改drawer_list_item.xml文件,使用自定义的属性

<?xml version="1.0" encoding="UTF-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/myapp_activatedBackgroundIndicator"
android:gravity="center_vertical"
android:minHeight="?attr/myapp_listPreferredItemHeightSmall"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textAppearance="?attr/myapp_textAppearanceListItemSmall" />

2)在
values/attrs.xml文件中声明自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AppTheme"> <!-- Attributes below are needed to support the navigation drawer on Android 3.x. -->
<!-- A smaller, sleeker list item height. -->
<attr name="myapp_listPreferredItemHeightSmall" format="dimension" /> <!-- Drawable used as a background for activated items. -->
<attr name="myapp_activatedBackgroundIndicator" format="reference" /> <!-- The preferred TextAppearance for the primary text of small list items. -->
<attr name="myapp_textAppearanceListItemSmall" format="reference" />
</declare-styleable>
</resources>

3)
在values-11/styles.xml文件中添加

  <!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<style name="AppBaseTheme" parent="Theme.Sherlock.Light.DarkActionBar"> <!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
<!-- Implementation of attributes needed for the navigation drawer as the default implementation is based on API-14. -->
<item name="myapp_listPreferredItemHeightSmall">48dip</item>
<item name="myapp_textAppearanceListItemSmall">@style/MyappDrawerMenu</item>
<item name="myapp_activatedBackgroundIndicator">@android:color/transparent</item>
</style> <style name="MyappDrawerMenu">
<item name="android:textSize">16sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@android:color/black</item>
</style>

4)
在values-v14/styles.xml文件中添加

<!--
Base application theme for API 14+. This theme completely replaces
AppBaseTheme from BOTH res/values/styles.xml and
res/values-v11/styles.xml on API 14+ devices.
-->
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- For API-14 and above the default implementation of the navigation drawer menu is used. Below APU-14 a custom implementation is used. -->
<item name="myapp_listPreferredItemHeightSmall">?android:attr/listPreferredItemHeightSmall</item>
<item name="myapp_textAppearanceListItemSmall">?android:attr/textAppearanceListItemSmall</item>
<item name="myapp_activatedBackgroundIndicator">?android:attr/activatedBackgroundIndicator</item>
</style>

OK,经过上面步骤,运行成功,这样上一篇的例子就能很好的适配到API 7了。

         

/**
* @author 张兴业

*  iOS入门群:83702688
*  android开发进阶群:241395671
*  我的新浪微博:@张兴业TBOW
*/

代码下载:Demo

Android UI开发第三十三篇——Navigation Drawer For Android API 7的更多相关文章

  1. Android UI开发第三十篇——使用Fragment构建灵活的桌面

    http://www.lupaworld.com/article-222973-1.html 当我们设计应用程序时,希望能够尽最大限度的适配各种设备,包括4寸屏.7寸屏. 10寸屏等等,Android ...

  2. Android UI开发第三十一篇——Android的Holo Theme

    好长时间没写Android UI方面的文章了,今天就闲扯一下Android的Holo主题.一直做android开发的可能都知道,Android 系统的UI有过两次大的变化,一次是android 3.0 ...

  3. 【转】Android UI开发第三十一篇——Android的Holo Theme

    好长时间没写Android UI方面的文章了,今天就闲扯一下Android的Holo主题.一直做android开发的可能都知道,Android 系统的UI有过两次大的变化,一次是android 3.0 ...

  4. Android UI开发第四十三篇——使用Property Animation实现墨迹天气3.0引导界面及动画实现

    前面写过<墨迹天气3.0引导界面及动画实现>,里面完美实现了动画效果,那一篇文章使用的View Animation,这一篇文章使用的Property Animation实现.Propert ...

  5. Android UI开发第三十九篇——Tab界面实现汇总及比较

    Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...

  6. Android UI开发第三十五篇——AppCompat实现Action Bar

    每一位Android开发者对Action Bar这种设计都不陌生了,毕竟它已经发布了至少两年了.Android团队发布Action Bar设计规范时同时放出了ActionBar的Api来支持这种设计. ...

  7. Android UI开发第二十八篇——Fragment中使用左右滑动菜单

    Fragment实现了Android UI的分片管理,尤其在平板开发中,好处多多.这一篇将借助Android UI开发第二十六篇——Fragment间的通信. Android UI开发第二十七篇——实 ...

  8. Android UI开发第三十二篇——Creating a Navigation Drawer

    Navigation Drawer是从屏幕的左侧滑出,显示应用导航的视图.官方是这样定义的: The navigation drawer is a panel that displays the ap ...

  9. Android UI开发第三十四篇——SlidingPaneLayout

    SlidingPaneLayout也是系统支持的高级控件,是Android团对在2013 google IO大会期间更新的Support库(Version 13)中新加入的重要的功能.它支持左右滑动菜 ...

随机推荐

  1. eclipse 安装git插件

    Eclipse上安装GIT插件EGit及使用 博客分类: GIT   一.Eclipse上安装GIT插件EGit Eclipse的版本eclipse-java-helios-SR2-win32.zip ...

  2. 练习--LINUX进程间通信之有名管理FIFO

    从FIFO中读取数据: 约定:如果一个进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作. 如果有进程写打开FIFO,且当前FIFO内没有数据,则对于设置了 ...

  3. PHP unlink() 函数

    定义和用法 unlink() 函数删除文件. 若成功,则返回 true,失败则返回 false. 语法 unlink(filename,context) 参数 描述 filename 必需.规定要删除 ...

  4. 同步两台linux服务器时间同步方案

    Linux自带了ntp服务 -- /etc/init.d/ntpd,这个服务不仅可以设置让本机和某台/某些机器做时间同步,他本身还可以扮演一个time server的角色,让其他机器和他同步时间. 配 ...

  5. 【Uva 12558】 Egyptian Fractions (HARD version) (迭代加深搜,IDA*)

    IDA* 就是iterative deepening(迭代深搜)+A*(启发式搜索) 启发式搜索就是设计估价函数进行的搜索(可以减很多枝哦~) 这题... 理论上可以回溯,但是解答树非常恐怖,深度没有 ...

  6. Linux设备驱动程序:中断处理之顶半部和底半部

    http://blog.csdn.net/yuesichiu/article/details/8286469 设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽可 ...

  7. 为什么要重写equals()方法与hashCode()方法

    在java中,所有的对象都是继承于Object类.Ojbect类中有两个方法equals.hashCode,这两个方法都是用来比较两个对象是否相等的. 在未重写equals方法我们是继承了object ...

  8. matlab numpy equivalents

    THIS IS AN EVOLVING WIKI DOCUMENT. If you find an error, or can fill in an empty box, please fix it! ...

  9. bzoj1670

    第一道凸包 采用Andrew算法,不论实现还是理解都非常简单 ..] of longint;     i,j,k,m,n:longint;     ans:double; procedure swap ...

  10. phpcms v9会员中心文件上传漏洞

    漏洞版本: phpcms v9 漏洞描述: PHPCMS V9采用OOP(面向对象)方式自主开发的框架.框架易扩展,稳定且具有超强大负载能力. phpcms v9会员中心上传头像处可未经过充分过滤,攻 ...