Fragment使用,替代Activity
1.Fragment的初衷:为了让界面可以在平板上更好地展示,Android在3.0版本引入了Fragment(碎片)功能,它非常类似于Activity,可以像Activity一样包含布局。Fragment通常是嵌套在Activity中使用的。需要注意,Fragment是在3.0版本引入的,如果你使用的是3.0之前的系统,需要先导入android-support-v4的jar包才能使用Fragment功能。
静态生成
1.Fragment的layout.xml配置文件fragment1:所有的Activity中能使用的布局在fragment中都能使用,其使用方式也一样如:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" 4 android:background="#ffff00" > 5 6 <TextView 7 android:layout_width="wrap_content" 8 android:layout_height="wrap_content" 9 android:text="This is fragment 2" 10 android:textColor="#000000" 11 android:textSize="25sp" /> 12 <ImagView 13 <ListView 14 . 15 . 16 . 17 18 </LinearLayout>
2.创建Fragment类Fragment1:继承自Fragment并重写onCreateView()方法
1 public class Fragment1 extends Fragment { 2 3 @Override 4 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 5 //R.layout.fragment1:fragment的layout.xml配置文件 6 return inflater.inflate(R.layout.fragment1, container, false); 7 } 8 }
3.在Main_Activity中的layout配置文件中加入Fragment1引用:使用android:name前缀来引用具体的Fragment:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:baselineAligned="false" > <fragment android:id="@+id/fragment1" android:name="com.example.fragmentdemo.Fragment1" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout>
4.运行Main_Activity则可以看到在fragment1布局文件中的UI控件:自动生成
1 public class MainActivity extends Activity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 } 8 9 }
动态生成:Fragment真正的强大之处在于可以动态地添加到Activity当中,因此这也是你必须要掌握的东西。当你学会了在程序运行时向Activity添加Fragment,程序的界面就可以定制的更加多样化。
1.获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。
2.开启一个事务,通过调用beginTransaction方法开启。
3.向容器内加入Fragment,一般使用replace方法实现,需要传入容器的id和Fragment的实例。
4.提交事务,调用commit方法提交。
如上例:将其中对Fragment的引用都删除,只保留最外层的LinearLayout,并给它添加一个id,因为我们要动态添加Fragment,不用在XML里添加了
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:id="@+id/main_layout" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:baselineAligned="false" > 6 </LinearLayout>
打开MainActivity,修改其中的代码:
1 public class MainActivity extends Activity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main);
//获取屏幕对象引用 7 Display display = getWindowManager().getDefaultDisplay();
//根据屏幕的宽,高添加不同的fragment 8 if (display.getWidth() > display.getHeight()) { 9 Fragment1 fragment1 = new Fragment1(); 10 getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit(); 11 } else { 12 Fragment2 fragment2 = new Fragment2(); 13 getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment2).commit(); 14 } 15 } 17 }
Fragment的生命周期:与Activity的生命周期很相似
- onAttach方法:Fragment和Activity建立关联的时候调用。
- onCreateView方法:为Fragment加载布局时调用。
- onActivityCreated方法:当Activity中的onCreate方法执行完后调用。
- onDestroyView方法:Fragment中的布局被移除时调用。
- onDetach方法:Fragment和Activity解除关联的时候调用。
Fragment之间进行通信:在同一个Activity中一般有多个Fragment,Fragment之间的通信一般通过getActivity()来得到相关联的Activity对象,
通过Activity对象中的findViewById()方法找到其它控件,进而达到Fragment交互。一般通过Fragment的生命周期来控制
1 public class Fragment2 extends Fragment { 2 3 @Override 4 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 5 return inflater.inflate(R.layout.fragment2, container, false); 6 } 8 @Override 9 public void onActivityCreated(Bundle savedInstanceState) { 10 super.onActivityCreated(savedInstanceState); 11 Button button = (Button) getActivity().findViewById(R.id.button); 12 button.setOnClickListener(new OnClickListener() { 13 @Override 14 public void onClick(View v) {
//通过fragment2中的按钮事件来触发拿到fragment1中的textView 15 TextView textView = (TextView) getActivity().findViewById(R.id.fragment1_text); 16 Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show(); 17 } 18 }); 19 } 21 }
Fragment碎片替代ActivityGroup:实现导航(QQ,微信,,,,)
1.整个Activity布局为一个fragment,及四个由ImagView,TextView组成的类似按钮的控件组成。
2.Activity中的主要代码逻辑:
1 public class MainActivity extends Activity implements OnClickListener { 2 @Override 3 protected void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 requestWindowFeature(Window.FEATURE_NO_TITLE); 6 setContentView(R.layout.activity_main); 7 // 初始化布局元素 8 initViews(); 9 fragmentManager = getFragmentManager(); 10 // 第一次启动时选中第0个tab 11 setTabSelection(0); 12 } 13 @Override 14 public void onClick(View v) { 15 switch (v.getId()) { 16 case R.id.message_layout: 17 // 当点击了消息tab时,选中第1个tab 18 setTabSelection(0); 19 break; 20 case R.id.contacts_layout: 21 // 当点击了联系人tab时,选中第2个tab 22 setTabSelection(1); 23 break; 24 case R.id.news_layout: 25 // 当点击了动态tab时,选中第3个tab 26 setTabSelection(2); 27 break; 28 case R.id.setting_layout: 29 // 当点击了设置tab时,选中第4个tab 30 setTabSelection(3); 31 break; 32 default: 33 break; 34 } 35 } 36 private void setTabSelection(int index) { 37 // 每次选中之前先清楚掉上次的选中状态 38 clearSelection(); 39 // 开启一个Fragment事务 40 FragmentTransaction transaction = fragmentManager.beginTransaction(); 41 // 先隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上的情况 42 hideFragments(transaction); 43 switch (index) { 44 case 0: 45 // 当点击了消息tab时,改变控件的图片和文字颜色 46 messageImage.setImageResource(R.drawable.message_selected); 47 messageText.setTextColor(Color.WHITE); 48 if (messageFragment == null) { 49 // 如果MessageFragment为空,则创建一个并添加到界面上 50 messageFragment = new MessageFragment(); 51 transaction.add(R.id.content, messageFragment); 52 } else { 53 // 如果MessageFragment不为空,则直接将它显示出来 54 transaction.show(messageFragment); 55 } 56 break; 57 case 1: 58 // 当点击了联系人tab时,改变控件的图片和文字颜色 59 contactsImage.setImageResource(R.drawable.contacts_selected); 60 contactsText.setTextColor(Color.WHITE); 61 if (contactsFragment == null) { 62 // 如果ContactsFragment为空,则创建一个并添加到界面上 63 contactsFragment = new ContactsFragment(); 64 transaction.add(R.id.content, contactsFragment); 65 } else { 66 // 如果ContactsFragment不为空,则直接将它显示出来 67 transaction.show(contactsFragment); 68 } 69 break; 70 case 2: 71 // 当点击了动态tab时,改变控件的图片和文字颜色 72 newsImage.setImageResource(R.drawable.news_selected); 73 newsText.setTextColor(Color.WHITE); 74 if (newsFragment == null) { 75 // 如果NewsFragment为空,则创建一个并添加到界面上 76 newsFragment = new NewsFragment(); 77 transaction.add(R.id.content, newsFragment); 78 } else { 79 // 如果NewsFragment不为空,则直接将它显示出来 80 transaction.show(newsFragment); 81 } 82 break; 83 case 3: 84 default: 85 // 当点击了设置tab时,改变控件的图片和文字颜色 86 settingImage.setImageResource(R.drawable.setting_selected); 87 settingText.setTextColor(Color.WHITE); 88 if (settingFragment == null) { 89 // 如果SettingFragment为空,则创建一个并添加到界面上 90 settingFragment = new SettingFragment(); 91 transaction.add(R.id.content, settingFragment); 92 } else { 93 // 如果SettingFragment不为空,则直接将它显示出来 94 transaction.show(settingFragment); 95 } 96 break; 97 } 98 transaction.commit(); 99 } 100 101 /** 102 * 清除掉所有的选中状态。 103 */ 104 private void clearSelection() { 105 messageImage.setImageResource(R.drawable.message_unselected); 106 messageText.setTextColor(Color.parseColor("#82858b")); 107 contactsImage.setImageResource(R.drawable.contacts_unselected); 108 contactsText.setTextColor(Color.parseColor("#82858b")); 109 newsImage.setImageResource(R.drawable.news_unselected); 110 newsText.setTextColor(Color.parseColor("#82858b")); 111 settingImage.setImageResource(R.drawable.setting_unselected); 112 settingText.setTextColor(Color.parseColor("#82858b")); 113 } 114 115 /** 116 * 将所有的Fragment都置为隐藏状态。 117 * 118 * @param transaction 119 * 用于对Fragment执行操作的事务 120 */ 121 private void hideFragments(FragmentTransaction transaction) { 122 if (messageFragment != null) { 123 transaction.hide(messageFragment); 124 } 125 if (contactsFragment != null) { 126 transaction.hide(contactsFragment); 127 } 128 if (newsFragment != null) { 129 transaction.hide(newsFragment); 130 } 131 if (settingFragment != null) { 132 transaction.hide(settingFragment); 133 } 134 } 135 }
主要逻辑功能实现:首先第一步是调用clearSelection()方法来清理掉之前的选中状态,然后开启一个Fragment事务,并隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上。接下来根据传入的index参数判断出选中的是哪一个Tab项,并改变该Tab项的图标和文字颜色,然后将相应的Fragment添加到界面上。这里注意一个细节,我们添加Fragment的时候并没有使用replace()方法,而是会先判断一下该Fragment是否为空,如果是空的则调用add()方法添加一个进来,如果不是空的则直接调用show()方法显示出来即可。那么为什么没有使用replace()方法呢?这是因为replace()方法会将被替换掉的那个Fragment彻底地移除掉,该Fragment的生命周期就结束了。当再次点击刚才那个Tab项的时候,就会让该Fragment的生命周期重新开始,onCreate()、onCreateView()等方法都会重新执行一遍。这显然不是我们想要的,也和ActivityGroup的工作原理不符,因此最好的解决方案就是使用hide()和show()方法来隐藏和显示Fragment,这就不会让Fragment的生命周期重走一遍了。