嵌套Tab在Android应用中用途广泛,之前做过的一些东西都是运用了TabActivity。但是由于在Android Developers中说到了“TabActivity was deprecated in API level 13." ,并且建议大家使用Fragment。所以学习了嵌套Fragment的使用,参考了这个博客中的相关思路和代码。
在Android Developers中对于 Fragment( 中文版看这里)的描述: A
Fragment represents a behaviors or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of
an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running.
简单来说,Fragment就是被嵌入在Activity中用来表现UI的一个可模块化和可重用的组件。Fragment在大屏幕设备中应用可以非常广泛,开发者可以通过自己巧妙的设计让UI更加灵活和美观。
创建Fragment
创建Fragment,必须创建一个Fragment的子类。
创建一个自己的Fragment,需要创建一个Fragment的子类。Fragment的生命周期和Activity的生命周期类似,它包含了很多与Activity类似的回调函数。
- public void onCreate (Bundle savedInstanceState)
创建fragment的时候调用onCreate()方法
- public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
在第一次绘制UI的时候系统调用该方法,为了绘制UI,返回一个fragment布局的根View。
将Fragment添加到Activity的方法
1.在layout文件中声明fragment
- <FrameLayout
- android:id="@+id/fragment_container"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:background="#fffab3" >
- </FrameLayout>
2.将一个fragment添加到viewgroup中,使用FragmentTransaction添加、替换或者删除fragment。
- private void addFragmentToStack(Fragment fragment) {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- ft.replace(R.id.fragment_container, fragment);
- ft.commit();
- }
Fragment生命周期
异常分析
关于解决 java.lang.IllegalStateException The specified child already has a parent. You must call removeView()的方法
在运行调试的时候会发现,在第二次点击一个相同的tab的时候,会出现上述异常。
这个异常说的是,这个特定的child view已经存在一个parent
view了,必须让parent view调用removeView()方法。
经过对fragment的生命周期的分析
运行顺序:点击tab1,点击tab2,再点击tab1.
具体fragment的生命周期是:
对上图进行分析,可以发现,出问题的是viewpager中的view。当切换不同的viewpager(即fragment,每个fragment中装载了一个viewpager)时,调用了startActivity()方法的时候,传入了相同的id,会返回相同的对象。而当我们在第二次调用的时候,传入了相同的id是复用了原来的view,这就导致了view被指定多个parent
view。
所以解决办法就是,在使用这个view之前首先判断其是否存在parent
view,这调用getParent()方法可以实现。如果存在parent
view,那么就调用removeAllViewsInLayout()方法。代码如下:
- for (View view : viewList) {
- ViewGroup p = (ViewGroup) view.getParent();
- if (p != null) {
- p.removeAllViewsInLayout();
- }
- }
结果展示
完成之后在模拟器中运行的效果如图:
主要代码
TestFragmentActivity.java
- package com.test;
-
- import java.util.ArrayList;
-
- import android.annotation.SuppressLint;
- import android.app.LocalActivityManager;
- import android.content.Intent;
- import android.os.Bundle;
- import android.support.v4.app.Fragment;
- import android.support.v4.app.FragmentActivity;
- import android.support.v4.app.FragmentTransaction;
- import android.support.v4.view.PagerAdapter;
- import android.support.v4.view.ViewPager;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.view.Window;
- import android.widget.LinearLayout;
-
- /**
- * 嵌套Fragment的使用
- *
- * @author zouliping
- *
- */
- public class TestFragmentActivity extends FragmentActivity {
-
- private LocalActivityManager manager;
-
- private ArrayList<View> list1 = new ArrayList<View>();
- private ArrayList<View> list2 = new ArrayList<View>();
- private ArrayList<View> list3 = new ArrayList<View>();
-
- private Fragment[] fragments;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.test_fragments);
-
- manager = new LocalActivityManager(this, false);
- manager.dispatchCreate(savedInstanceState);
-
- initViews();
- }
-
- /**
- * 初始化Views
- */
- private void initViews() {
- findViewById(R.id.tv1).setOnClickListener(listener);
- findViewById(R.id.tv2).setOnClickListener(listener);
- findViewById(R.id.tv3).setOnClickListener(listener);
-
- fragments = new FragmentParent[3];
- fragments[0] = FragmentParent.newInstance(list1, new String[] {
- "page1_1", "page1_2", "page1_3" });
- fragments[1] = FragmentParent.newInstance(list2, new String[] {
- "page2_1", "page2_2", "page2_3" });
- fragments[2] = FragmentParent.newInstance(list3, new String[] {
- "page3_1", "page3_2", "page3_3" });
-
- initPager();
-
- findViewById(R.id.tv1).performClick();
- }
-
- /**
- * 获取view
- *
- * @param id
- * @param intent
- * @return
- */
- private View getView(String id, Intent intent) {
- return manager.startActivity(id, intent).getDecorView();
- }
-
- /**
- * 根据parent position初始化viewPager
- */
- private void initPager() {
- Intent intent;
-
- // tab1
- intent = new Intent(TestFragmentActivity.this, Test1Activity.class);
- list1.add(getView("tab1_1", intent));
- intent = new Intent(TestFragmentActivity.this, Test2Activity.class);
- list1.add(getView("tab1_2", intent));
- intent = new Intent(TestFragmentActivity.this, Test1Activity.class);
- list1.add(getView("tab1_3", intent));
-
- // tab2
- intent = new Intent(TestFragmentActivity.this, Test1Activity.class);
- list2.add(getView("tab2_1", intent));
- intent = new Intent(TestFragmentActivity.this, Test2Activity.class);
- list2.add(getView("tab2_2", intent));
- intent = new Intent(TestFragmentActivity.this, Test1Activity.class);
- list2.add(getView("tab2_3", intent));
-
- // tab3
- intent = new Intent(TestFragmentActivity.this, Test1Activity.class);
- list3.add(getView("tab2_1", intent));
- intent = new Intent(TestFragmentActivity.this, Test2Activity.class);
- list3.add(getView("tab2_2", intent));
- intent = new Intent(TestFragmentActivity.this, Test1Activity.class);
- list3.add(getView("tab2_3", intent));
- }
-
- private OnClickListener listener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.tv1:
- addFragmentToStack(fragments[0]);
- break;
- case R.id.tv2:
- addFragmentToStack(fragments[1]);
- break;
- case R.id.tv3:
- addFragmentToStack(fragments[2]);
- break;
- }
-
- }
- };
-
- private void addFragmentToStack(Fragment fragment) {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- ft.replace(R.id.fragment_container, fragment);
- ft.commit();
- }
-
- /**
- * 嵌套Fragment
- *
- */
- @SuppressLint("ValidFragment")
- public final static class FragmentParent extends Fragment {
-
- /**
- * 工厂方法,返回一个新的FragmentParent的实例
- *
- * @param list
- * @param str
- * @return
- */
- public static final FragmentParent newInstance(ArrayList<View> list,
- String[] str) {
- FragmentParent framentParent = new FragmentParent();
- Bundle bundle = new Bundle();
- bundle.putSerializable("pager_view_list", list);
- bundle.putStringArray("pager_title_ary", str);
- framentParent.setArguments(bundle);
- return framentParent;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- Log.d("test fragment", "fragment create view");
-
- LinearLayout convertView = (LinearLayout) inflater.inflate(
- R.layout.viewpager_fragments, container, false);
- ViewPager pager = (ViewPager) convertView.findViewById(R.id.pager);
-
- @SuppressWarnings("unchecked")
- final ArrayList<View> viewList = (ArrayList<View>) getArguments()
- .getSerializable("pager_view_list");
- final String[] titles = getArguments().getStringArray(
- "pager_title_ary");
-
- for (View view : viewList) {
- ViewGroup p = (ViewGroup) view.getParent();
- if (p != null) {
- p.removeAllViewsInLayout();
- }
- }
-
- pager.setAdapter(new PagerAdapter() {
-
- @Override
- public boolean isViewFromObject(View view, Object obj) {
- return view == obj;
- }
-
- @Override
- public int getCount() {
- return viewList.size();
- }
-
- @Override
- public void destroyItem(ViewGroup container, int position,
- Object object) {
- container.removeView(viewList.get(position));
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- return titles[position];
- }
-
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- container.addView(viewList.get(position));
- return viewList.get(position);
- }
- });
-
- return convertView;
- }
-
- @Override
- public void onStart() {
- super.onStart();
- Log.d("test fragment", "fregment start");
- }
-
- @Override
- public void onStop() {
- super.onStop();
- Log.d("test fragment", "fregment stop");
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Log.d("test fragment", "fregment resume");
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.d("test fragment", "fregment destroy");
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- Log.d("test fragment", "fregment detach");
- }
-
- }
- }
布局文件 test_fragments.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas./apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <FrameLayout
- android:id="@+id/fragment_container"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:background="#fffab3" >
- </FrameLayout>
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:background="@android:color/black"
- android:orientation="horizontal" >
-
- <TextView
- android:id="@+id/tv1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="10dp"
- android:layout_marginLeft="10dp"
- android:layout_marginTop="10dp"
- android:text="tab1"
- android:textColor="#ffffff"
- android:textIsSelectable="true"
- android:textSize="25sp" />
-
- <TextView
- android:id="@+id/tv2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="10dp"
- android:layout_marginLeft="15dp"
- android:layout_marginTop="10dp"
- android:text="tab2"
- android:textColor="#ffffff"
- android:textIsSelectable="true"
- android:textSize="25sp" />
-
- <TextView
- android:id="@+id/tv3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="10dp"
- android:layout_marginLeft="15dp"
- android:layout_marginTop="10dp"
- android:text="tab3"
- android:textColor="#ffffff"
- android:textIsSelectable="true"
- android:textSize="25sp" />
- </LinearLayout>
-
- </LinearLayout>
|