使用Fragment完成Tab选项卡-Android Fragment应用实战

来源:互联网 发布:淘宝代销好吗 编辑:程序博客网 时间:2024/04/29 17:38

先看一下QQ、新浪微博、支付宝钱包这三个非常有名的应用,都有一个底部导航栏,我们一般称之‘选项卡’。google官方会叫他们为fixed tab,不过国内好像很好这么叫的。其实,在anroid 4.x时代,google官方更希望应用的导航放在顶部,通过滑屏和点击标签来切换界面。但是随着ios的的跟风以及用户习惯的养成,这种设计风格的形成也就变成历史遗留问题。在这里我们不讨论哪一个风格好,哪一个风格不好。做为开发人员,我们可能更关注这种司空见惯的界面设计是怎么实现的呢?

        

在android 2.x时代,我们可能会地使用ActivityGroup来实现这种,但是随着jelly bean的市场份额超过50%,我们会发现有一种新的组建出现了,它叫Fragment(http://developer.android.com/reference/android/app/Fragment.html)。而这种底部选项卡的风格界面的实现也由ActivityGroup转向了Fragment。先了,费话不多说了,下面我会一步一步教您怎么实现这个界面。在动手之前,我可能需要把我做好的样式图给你看一下,以遍让您有一个心里预期。



其实,我们这个界面的实现,基本没有什么java 代码。不信,你看下面就是主界面的代码:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class MainActivity extends Activity {  
  2.     private FragmentManager fragmentManager;  
  3.     private RadioGroup radioGroup;  
  4.   
  5.     @TargetApi(Build.VERSION_CODES.HONEYCOMB)  
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  10.         setContentView(R.layout.weibo_tab);  
  11.   
  12.         fragmentManager = getFragmentManager();  
  13.         radioGroup = (RadioGroup) findViewById(R.id.rg_tab);  
  14.         radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {  
  15.             @Override  
  16.             public void onCheckedChanged(RadioGroup group, int checkedId) {  
  17.                 FragmentTransaction transaction = fragmentManager.beginTransaction();  
  18.                 Fragment fragment = FragmentFactory.getInstanceByIndex(checkedId);  
  19.                 transaction.replace(R.id.content, fragment);  
  20.                 transaction.commit();  
  21.             }  
  22.         });  
  23.     }  
  24.   
  25. }  

所以哦,亲们,我们把重点放在xml界面的编写上咯。

1.我们可能需要一背景图片像这样的:

2.我们要准备这五个选项卡图片。包括正常和被按下两种状态。所以共十张图片。

3.你要为这五个按钮分别编写selector,文件名为weibolist_attention_selector.xml

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?><!-- 微博列表界面tab栏关注 按钮 -->  
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <item android:drawable="@drawable/weibo_listab_attention_on" android:state_pressed="true" />  
  4.     <item android:drawable="@drawable/weibo_listab_attention_on" android:state_checked="true" />  
  5.     <item android:drawable="@drawable/weibo_listab_attention_off" />  
  6. </selector>  
这个xml文件挺简单的啊,但是细心的同学可能会地现,你这里为什么要用android:state_checked的啊?为什么不是其他的,比如android:state_selected哦

我想说,其实我这个底部用的是RadioGroup,我怎么判断当前选中的是哪个呢,不选中的是哪个呢。这里最好的选择就是使用RadioGroup,它的最大好处就是彼此的RadioButton具有互斥性,这样就费掉用java代码判断和处理的麻烦了。

4.下面,就要考虑为整个界面布局了。文件名为activity.xml

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <LinearLayout  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical"  
  7.     xmlns:android="http://schemas.android.com/apk/res/android">  
  8.   
  9.   
  10.     <FrameLayout  
  11.         android:id="@+id/content"  
  12.         android:layout_width="match_parent"  
  13.         android:layout_height="match_parent"  
  14.         android:layout_weight="1" />  
  15.   
  16.     <RadioGroup  
  17.         android:id="@+id/rg_tab"  
  18.         android:orientation="horizontal"  
  19.         android:layout_width="match_parent"  
  20.         android:layout_height="wrap_content"  
  21.         android:background="@drawable/bg_weibo_listab">  
  22.   
  23.         <RadioButton  
  24.             style="@style/weibo_tab"  
  25.             android:drawableTop="@drawable/weibolist_attention_selector"  
  26.             android:text="微博" />  
  27.   
  28.         <RadioButton  
  29.             style="@style/weibo_tab"  
  30.             android:drawableTop="@drawable/weibolist_atme_selector"  
  31.             android:text="\@我" />  
  32.   
  33.         <RadioButton  
  34.             style="@style/weibo_tab"  
  35.             android:drawableTop="@drawable/weibolist_comment_selector"  
  36.             android:text="评论" />  
  37.   
  38.         <RadioButton  
  39.             style="@style/weibo_tab"  
  40.             android:drawableTop="@drawable/weibolist_mylist_selector"  
  41.             android:text="我的" />  
  42.   
  43.         <RadioButton  
  44.             style="@style/weibo_tab"  
  45.             android:drawableTop="@drawable/weibolist_global_selector"  
  46.             android:text="全站" />  
  47.     </RadioGroup>  
  48. </LinearLayout>  
这里可能就有几个问题啦

(1) FrameLayout是干什么的,可能用别的父控件吗?

     这个是一个预留的内容控件,以后会用它去呈现Fragment的内容。理论上是可以用别的父控件的,没试过。

(2)android:weight=1,怎么只有一个呢,这样做有对LinearLayout有意义吗?

     首先对FragLayout一定要写,不写就会变成这样。但是第二个RadioGroup的weight一定不要写,不然会很难调的。这个我猜测应该会有一个很好weight缺省值自适应的。

     我只是猜测啦,具体原因求解释。

(3)weibo_tab样式里面什么内容?

    什么内容,如下就可以啦:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <style name="weibo_tab">  
  2.     <item name="android:layout_height">wrap_content</item>  
  3.     <item name="android:layout_width">match_parent</item>  
  4.     <item name="android:layout_weight">1</item>  
  5.     <item name="android:gravity">center</item>  
  6.     <item name="android:textSize">14sp</item>  
  7.     <item name="android:paddingTop">8dip</item>  
  8.     <item name="android:paddingBottom">4dip</item>  
  9.     <item name="android:background">@drawable/weibolist_bottombar_itembg_selector</item>  
  10.     <item name="android:textColor">@color/weibolist_bottombar_textcolor_selector</item>  
  11.     <item name="android:button">@null</item>  
  12. </style>  
    这个style的目地是为了把button相同的设置提取出来,进行很好地重构。
    这里可能要解释几个属性weight,其实RadioGroup是继承LinearLayout,设置weight的目的就是把这个底部视图五等分。

    textColor,这是为是控制底部颜色变化的。button,这个一定要设置,否则就会这样


   做到这里,我建议你就跑起来,试试效果。虽然没有用到Fragment,但是底部选项已经可以任意切换啦。

   你是不是已经把它很好的搞定了呢,先恭喜你咯。大笑

5.下一步我来内容填充的界面视图,文件名为fragment.xml

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent">  
  5.   
  6.     <TextView  
  7.         android:id="@+id/txt_content"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent"  
  10.         android:gravity="center"  
  11.         android:padding="10dp"  
  12.         android:text=""  
  13.         android:textSize="20sp" />  
  14. </RelativeLayout>  
这个没有什么解释的,略过。

6.下面我们做五个Fragment内容的呈现,如下:

先有一个BaseFragment抽象类,以被具体的子类继承和实现。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1.   
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public abstract class BaseFragment extends Fragment {  
  2.     @Override  
  3.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  4.         View view = inflater.inflate(R.layout.fragment, null);  
  5.         TextView textView = (TextView) view.findViewById(R.id.txt_content);  
  6.         textView.setText(initContent());  
  7.         return view;  
  8.     }  
  9.   
  10.     public abstract String initContent();  
  11. }  

(1)关注界面

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class AttentionFragment extends BaseFragment {  
  2.     @Override  
  3.     public String initContent() {  
  4.         return "这是关注我界面";  
  5.     }  
  6. }  
(2)@界面

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class AtmeFragment extends BaseFragment {  
  2.   
  3.     @Override  
  4.     public String initContent() {  
  5.         return "这是@我界面";  
  6.     }  
  7. }  
(3)评论界面

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class CommentFragment extends BaseFragment {  
  2.     @Override  
  3.     public String initContent() {  
  4.         return "这是评论我界面";  
  5.     }  
  6. }  
(4)我的界面

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class MyListFragment extends BaseFragment {  
  2.     @Override  
  3.     public String initContent() {  
  4.         return "这是我的列表界面";  
  5.     }  
  6. }  
(5)全部界面

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class GlobalFragment extends BaseFragment {  
  2.     @Override  
  3.     public String initContent() {  
  4.         return "这是全站界面";  
  5.     }  
  6. }  

7.我们还需要一个工厂模式,来实现根据下标的位置返回相应的Fragment。像这样

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class FragmentFactory {  
  2.     public static Fragment getInstanceByIndex(int index) {  
  3.         Fragment fragment = null;  
  4.         switch (index) {  
  5.             case 1:  
  6.                 fragment = new AttentionFragment();  
  7.                 break;  
  8.             case 2:  
  9.                 fragment = new AtmeFragment();  
  10.                 break;  
  11.             case 3:  
  12.                 fragment = new CommentFragment();  
  13.                 break;  
  14.             case 4:  
  15.                 fragment = new MyListFragment();  
  16.                 break;  
  17.             case 5:  
  18.                 fragment = new GlobalFragment();  
  19.                 break;  
  20.         }  
  21.         return fragment;  
  22.     }  
  23. }  

8.好了,万事具备只欠东风啦。请回到我们刚开始放出去那段代码,那你就已经完成它了。

9.哦,我们还是放上配置文件,贡大家参考。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     package="com.mydream.fragment"  
  3.     android:versionCode="1"  
  4.     android:versionName="1.0">  
  5.   
  6.     <uses-sdk  
  7.         android:minSdkVersion="14"  
  8.         android:targetSdkVersion="19" />  
  9.   
  10.     <application  
  11.         android:allowBackup="true"  
  12.         android:label="@string/app_name"  
  13.         android:icon="@drawable/ic_launcher">  
  14.         <activity  
  15.             android:name=".MainActivity"  
  16.             android:label="@string/app_name">  
  17.             <intent-filter>  
  18.                 <action android:name="android.intent.action.MAIN" />  
  19.   
  20.                 <category android:name="android.intent.category.LAUNCHER" />  
  21.             </intent-filter>  
  22.         </activity>  
  23.     </application>  
  24.   
  25. </manifest>  

源代码下载

0 0