Android 设置界面修改为Iphone的tab菜单风格

        好久没有写博客了!最近做了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);
			<span style="BACKGROUND-COLOR: #ff0000">MainHandler.sendEmptyMessageDelayed(222,195);
</span>		}
		else{
			TabSettings_ListView.startAnimation(slide_right_out);
			<span style="BACKGROUND-COLOR: #ff0000">MainHandler.sendEmptyMessageDelayed(000,195);
</span>		}
		mNext_SelectedTab = the_tap_index;
	}

  }

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

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

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

	@Override
	public 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包装了一下!这就是所有的!你应该了解了吧。




   

        

Android 设置界面修改为Iphone的tab菜单风格,布布扣,bubuko.com

Android 设置界面修改为Iphone的tab菜单风格

上一篇:java系统开发框架


下一篇:插件化(android)