预备知识
嵌套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 isrunning.
简单来说,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.android.com/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>
分享到:
相关推荐
在使用ViewPager + Fragment 的时候报错:The specified child already has a parent. You must call removeView() on the child’s parent first.
在使用ViewPager + Fragment 的时候报错:The specified child already has a parent. You must call removeView() on the child’s parent first
fragment嵌套fragment
都说fragment好用,duang~~,又遇到问题了,记录一下,分享给遇到这个问题的同学! 1.fragment嵌套fragment时出现getActivity()为null activity A嵌套fragment B,B嵌套fragment C,C跳转到activity D,当activity D...
viewpager中嵌套fragment,fragment再嵌套viewpager,然后viewpager再次嵌套。
Fragment内嵌套Fragment之间的切换
Fragment嵌套fragmen。对应的博客链接:http://blog.csdn.net/r_ine,其中有一篇是对其的介绍。这是一个 eclipse资源。
Activity嵌套fragment大全,activity加载单个fragment,TabLayout+ViewPager实现多个fragment滑动效果
Android ViewPager+Fragment嵌套使用Demo
Android 用正确的姿势在 Activity 里面嵌套 Fragment 。 博客文章地址:http://www.jianshu.com/p/07dfdef0c63f
多个fragment进行嵌套,AFragment里打开BFragment,在BFragment中按返回,返回上级fragment
这几天做项目遇到一个问题,就是有这么一个页面是activity嵌套一个fragment1然后fragment1里放了一个viewpager,viewpager里放了几个fragment,本来只有这么一个页面,显示出来也没什么问题,现在加新需求,要求点击...
android fragment 使用以及嵌套使用 底部菜单和顶部菜单,类似微信和QQ的分页菜单
嵌套Fragment在Eclipse中的工程。 具体博客地址:http://blog.csdn.net/zouliping123/article/details/8834361
fragment 嵌套fragment 嵌套fragment 嵌套fragment 嵌套fragment 嵌套
这是一个fragment嵌套fragment的demo,仅供参考。大神可以不必看
Fragment的嵌套和侧滑菜单DrawerLayout加标签页SlidingTabLayout的使用demo. android studio项目
viewPager + fragment实现基础的页面滑动效果,Fragment+Fragment实现滑动
原来做的一个练手的项目,里面主要是Fragment的嵌套,需要的朋友可以看下,如果遇到不能运行的状况可酌量删除些代码。
Android界面实现Fragment嵌套使用,类似苹果的选项卡界面