好久没有写博客了!最近做了Android 设置的列表菜单风格改为Iphone的tab菜单风格的尝试!我知道,有许多朋友有自己的方式已经实现了这个界面风格的开发,今天大家来看看我的做法吧!先看看如下图的效果:


做这个开发前,首先要看看Android默认的设置列表菜单风格的实现!由AndroidManifest.xml可以知道Settings这个Activity是我们关注的焦点!所以我们来到Settings.java来一探究竟,从中我们可以清除的知道他其实是一个PreferenceActivity,而PreferenceActivity又继承了ListActivity,我们知道ListActivity其实就是专门用于显示ListView的activity.这样一来,我们就清楚了,为什么显示的是列表菜单。实际上在Settings这个Activity里面利用这个函数loadHeadersFromResource来加载不同的xml配置文件,就可以加载对应的菜单了!在这个xml文件里面每一项菜单项几乎都定义了自己的fragment,这样一来,只要你点击对应的菜单就能进入对应的fragment了!

如果,你多关注一下Settings这个activity,你就会发现这个activity比你想象的要复杂的多!比如,在手机里面很多需要对手机设置的地方都可能调用Settings这个activity,想要通过改动这个activity来实现Iphone的tab菜单风格,我觉得要冒一定的风险!所以,在做Iphone的tab菜单风格的时候我提出了两个规则:

(1)尽量不影响Settings这个activity,包括这个activity的定义、已经被何时、何地被调用。

(2)尽量要求效率!

一般来说,做tab菜单风格无非有三种方式:(1)TabHost + ViewPager ;(2)ActionBar + ViewPager;(3)TabWidget + ViewPager;从中可以知道,都要用到ViewPager. 而ViewPager是通过Adapter加载不同的view来实现不同的tab的菜单显示!这样的话就需要你写一个activity,通过加载包含ViewPager 的layout来实现!这样一来的话,要实现这个效果,你就需要从写一个另外一直方式的Settings的activity,这显然是有风险的!然后来看看ActionBar能否实现Iphone的tab折中底部tab按钮的效果!答案是否定的!(网上有各种办法,我实验的结果是无法实现这种效果的)。

ok,来说说我的实现办法把!

首先,我选择TabActivity来取代原来Settings的Activity地位!定义自己的TabActivity:TabSetting,在AndroidManifest.xml里面改为:

        <activity android:name="TabSetting"                android:label="@string/settings_label_launcher"                android:taskAffinity="com.android.settings"                android:theme="@style/Theme.Settings.Light"        android:configChanges="keyboardHidden|screenSize|mcc|mnc"                android:launchMode="singleTask">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <action android:name="android.settings.SETTINGS" />                <category android:name="android.intent.category.DEFAULT" />                <category android:name="android.intent.category.LAUNCHER" />                <category android:name="android.intent.category.APP_SETTINGS" />            </intent-filter>        </activity>

原来的settings配置如下:

        <activity android:name="Settings"                      android:label="@string/settings_label_launcher"                      android:taskAffinity="com.android.settings"                      android:theme="@style/Theme.Settings.Light"                       android:configChanges="keyboardHidden|screenSize|mcc|mnc"                      android:launchMode="singleTask">        </activity>


然后来看看TabSetting这个Activity的布局文件的定义:

<?xml version="1.0" encoding="utf-8"?><TabHost android:id="@+android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"xmlns:android="http://schemas.android.com/apk/res/android">    <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">        <FrameLayout         android:id="@+android:id/tabcontent"         android:layout_width="fill_parent"         android:layout_height="fill_parent"         android:layout_weight="1.0" />        <TabWidget         android:orientation="horizontal"         android:id="@+android:id/tabs"         android:layout_width="fill_parent"         android:layout_height="57.0dip"         android:divider="@null"         style="?android:attr/tabWidgetStyle" />    </Linear

从上面的布局,我们就这里采用的是TabWidget.

接下来的重点就是TabHost的配置了!我们直接看代码:

 private void createTabs(int selectedIndex) {  mTabHost = getTabHost(); LinearLayout tab_view;  final LayoutInflater inflater = LayoutInflater.from(this); if (mTabHost != null) {   Intent start_activity_intent = TabSettings_content.getIntent_for_tab(this); start_activity_intent.putExtra(INIT_SELECTED_TAB, selectedIndex);      tab_view =(LinearLayout) inflater.inflate(tab_view_resource_id, mTabHost.getTabWidget(), false);    ((TextView)tab_view.findViewById(R.id.tab_hint)).setText(R.string.meng_tab_network);  ((ImageView)tab_view.findViewById(R.id.tab_icon)).setImageResource(R.drawable.xunhu_tab_network);    start_activity_intent.putExtra(SELECT_TAB_INTENT_EXTRA, NETWORK_TAB_INDEX);    mTabHost.addTab(mTabHost.newTabSpec("network")         .setIndicator(tab_view)         .set_SameContent(start_activity_intent));     tab_view =(LinearLayout) inflater.inflate(tab_view_resource_id, mTabHost.getTabWidget(), false); ((TextView)tab_view.findViewById(R.id.tab_hint)).setText(R.string.meng_tab_device);  ((ImageView)tab_view.findViewById(R.id.tab_icon)).setImageResource(R.drawable.xunhu_tab_device);    start_activity_intent =(Intent) start_activity_intent.clone();    start_activity_intent.putExtra(SELECT_TAB_INTENT_EXTRA, DEVICE_TAB_INDEX);    mTabHost.addTab(mTabHost.newTabSpec("device")         .setIndicator(tab_view)         .set_SameContent(start_activity_intent)); tab_view =(LinearLayout) inflater.inflate(tab_view_resource_id, mTabHost.getTabWidget(), false); ((TextView)tab_view.findViewById(R.id.tab_hint)).setText(R.string.meng_tab_personal);  ((ImageView)tab_view.findViewById(R.id.tab_icon)).setImageResource(R.drawable.xunhu_tab_personal);    start_activity_intent =(Intent) start_activity_intent.clone();    start_activity_intent.putExtra(SELECT_TAB_INTENT_EXTRA, PERSONAL_TAB_INDEX);    mTabHost.addTab(mTabHost.newTabSpec("personal")         .setIndicator(tab_view)         .set_SameContent(start_activity_intent)); tab_view =(LinearLayout) inflater.inflate(tab_view_resource_id, mTabHost.getTabWidget(), false); ((TextView)tab_view.findViewById(R.id.tab_hint)).setText(R.string.meng_tab_system);  ((ImageView)tab_view.findViewById(R.id.tab_icon)).setImageResource(R.drawable.xunhu_tab_system);//    start_activity_intent =(Intent) start_activity_intent.clone();    start_activity_intent.putExtra(SELECT_TAB_INTENT_EXTRA, SYSTEM_TAB_INDEX);    mTabHost.addTab(mTabHost.newTabSpec("system")         .setIndicator(tab_view)         .set_SameContent(start_activity_intent));    mTabHost.setOnTabChangedListener(new OnTabChangeListener() {     public void onTabChanged(String tabId) {      if (tabId.equals("network"))        {       mSelectedTab = NETWORK_TAB_INDEX;       }     else if(tabId.equals("device"))      {      mSelectedTab = DEVICE_TAB_INDEX;      }     else if(tabId.equals("personal"))      {      mSelectedTab = PERSONAL_TAB_INDEX;      }     else if(tabId.equals("system"))      {      mSelectedTab = SYSTEM_TAB_INDEX;      }     //mTabHost.setCurrentTab(mSelectedTab);     TabSetting.this.updateTabStyle(TabSetting.this.mTabHost);     }    }); }   }

这里请关注一下红色的代码!你会发现不同tab都配置了相同的intent。这是为什么呢!实际上这个start_activity_intent就是用于启动我们shettings的avtivity的!所以,我的目的其实就是不同tab菜单的切换其实都是用一个activity,而且这个activity就是系统原本有的shettings的activity。只是在不同的tab,loadHeadersFromResource加载不同的xml来实现显示不同的菜单!这里我们来看看这个我们启动的activity(TabSettings_content)的定义:

public class TabSettings_content extends Settings{private static final boolean DEBUG = true;    private static int mCurr_SelectedTab = TabSetting.NETWORK_TAB_INDEX;   private static int mNext_SelectedTab = TabSetting.NETWORK_TAB_INDEX;  private int SettingMenuStyle_index = -1;............}

从上面的代码可以知道 TabSettings_content其实就是一个Settings的封装。

那在TabSettings_content里面是怎么知道在不同的tab界面加载不同的xlm文件呢!这个时候activity的onNewIntent这个方法就有用处了!如下:

    @Override    public void onNewIntent(Intent newIntent) {        super.onNewIntent(newIntent);        // update our intent so that we can consult it to determine whether or        // not the most recent launch was via the event        setIntent(newIntent);        //Get the saved selected tap_index,         int tab = newIntent.getIntExtra(TabSetting.SELECT_TAB_INTENT_EXTRA, mCurr_SelectedTab);if (!getResources().getBoolean(R.bool.TabSettingPage_Change_Animal)){if(tab != mCurr_SelectedTab){mCurr_SelectedTab = tab;mNext_SelectedTab = mCurr_SelectedTab;invalidateHeaders();}        }else if (tab != -1 && tab != mCurr_SelectedTab) {<span style="BACKGROUND-COLOR: #ff0000">Switch_tab_anima(tab);</span>        }    }

从上面的代码,你可能有点晕,因为你不太知道Switch_tab_anima(tab);这个语句在做什么。通过字面的意思,可以知道这应该就是tab切换并且还播放动画了! 其实这里播放的动画其实就是左右两个tab往左边移出、右边tab从右边移入的这样的一个动画效果!下面代码来看看这个方法Switch_tab_anima的实现吧:

 private void Switch_tab_anima(int the_tap_index){ if(false == Init_Animation){ Init_Animation_Play(); }if (the_tap_index != mCurr_SelectedTab && the_tap_index != -1) {if((the_tap_index > mCurr_SelectedTab && !(the_tap_index == 3 && mCurr_SelectedTab == 0)) || (the_tap_index == 0 && mCurr_SelectedTab == 3)){TabSettings_ListView.startAnimation(slide_left_out);}else{TabSettings_ListView.startAnimation(slide_right_out);}mNext_SelectedTab = the_tap_index;}  }

一样的,上面有两行我标记红色的代码,这个地方MainHandler就是一个我定义的Handler,主要目的就是延时,其目的是:原来的tab移除以后,新的tab才开始移入。这里的延时就是等原来的tab移除。

最后,你会发现,我实现的这个tab菜单风格,当用手指左右滑动菜单时候,并不会切换到下一个tab(或者上一个tab),这怎么办呢!下面通过2步来实现:

(1):首先要能获取手指触摸屏的事件:这里你不得不选择dispatchTouchEvent:

@Overridepublic boolean dispatchTouchEvent(MotionEvent m) {// Elog.d(TAG, "dispatchTouchEvent()");Log.d("TabSetting", "TabSetting dispatchTouchEvent()");if (this.detector != null) {this.detector.onTouchEvent(m);}boolean flag = super.dispatchTouchEvent(m);Log.d("TabSetting", "TabSetting dispatchTouchEvent()  flag="+flag);return flag;}

(2):我们刚刚定义的TabActivity:TabSetting 需要实现OnGestureListener这个手势接口!该接口的onFling和onScroll来实现识别手指滑动的操作,操作成功则切换不同tab:下面代码是方法onFling的实现(和方法onScroll实现一样的):

 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int tab_index;          if(TouchedDown_Done == true){ return false; } if (e1.getX() - e2.getX() > <span style="BACKGROUND-COLOR: #ff0000">move_switch_len</span>) {    tab_index = mSelectedTab == 3 ? 0:mSelectedTab+1;   mTabHost.setCurrentTab(tab_index);   mSelectedTab = tab_index;   TouchedDown_Done = true;   return true; } else if(e2.getX() - e1.getX() > move_switch_len){ tab_index = mSelectedTab == 0 ? 3:mSelectedTab-1; mTabHost.setCurrentTab(tab_index); mSelectedTab = tab_index; TouchedDown_Done = true;     return true; } else{ return false; }   }

关注一下move_switch_len这个量吧。这个值不能太大也不能太小!你知道原因吗?

我想该说的已经说完了!我这里实现tab风格其实还是调用原来的Settings这个activity,只是外面用一个TabActivity包装了一下!这就是所有的!你应该了解了吧。




更多相关文章

  1. Android自定义View之View的绘制流程
  2. Android Metro风格的Launcher开发系列第一篇
  3. android菜单_Android:菜单类调查
  4. 一起Talk Android吧(第一百四十八回:Android自定义View之Layout五)
  5. Android 自定义Button按钮显示样式(正常、按下、获取焦点)
  6. Android--自定义视图控件(一)(Android Studio)
  7. Android自定义控件的使用
  8. 一个非常好用的自定义圆形控件
  9. Android的两种菜单

随机推荐

  1. android 配置ADB环境
  2. Android仿微信聊天界面
  3. 在Android使用正则表达式
  4. 更改android开机画面 DIY
  5. 【腾讯Bugly干货分享】Android进程保活招
  6. Android如何解析Intent Filter
  7. android中Intent的一些用法和总结
  8. Android系统各个版本 最新市场份额变换
  9. Android最全面、最易懂的Android屏幕适配
  10. Android 运行时权限处理(from jianshu)