当前位置: 代码迷 >> Iphone >> Android 设置界面修改为Iphone的tab菜单作派
  详细解决方案

Android 设置界面修改为Iphone的tab菜单作派

热度:54   发布时间:2016-04-25 05:46:48.0
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包装了一下!这就是所有的!你应该了解了吧。




   

        

  相关解决方案