1.1 Fragment的概念
【
Android 3.0引入的新特性:Fragment(碎片)
Fragment允许将Activity拆分成多个完全独立封装的可重用的组件
每个Fragment都有自己的生命周期和UI布局
Fragmnet必须依赖于Activity,不能单独存在
Fragmnet是一个轻量级的Activity
作用:
1. 如下图所示的,目前大部分软件的显示结构,特点在于:一旦通过按钮进行页面的切换时,只有上半部分进行切换,而Button按钮部分保持不变,为实现这样的效果,如果通过startActivity进行切换的话,只能实现整个页面连按钮部分带?部分一起换的效果。因此,3.0以后引进了碎片的概念,可以通过在页面中显示n个碎片,然后在点击按钮的时候,通过切换碎片实现部分切换的效果
2. 如上图所示的效果中,如果都写在同一个Activity中的话,所有的代码加起来会非常长,为了便于代码的后期修改管理,推荐将每一个模块的代码都放到一个对应的碎片类中进行统一的处理
Fragment的特点:
1. Fragment允许将Activity拆分成多个完全独立封装的可重用的组件
即:a. 一个Activity中可以显示多个Fragment
b. 一个Fragment也可以被拿到多个页面中进行显示
2. Fragmnet必须依赖于Activity,不能单独存在
即:即使页面上只显示一个Fragment,那么也必须是页面上显示Activity,Activity中显示Fragment,不能页面直接显示Fragment
3. 每个Fragment都有自己的生命周期和UI布局
】
1.2 Fragment的基本使用
【
1、定义类继承自Fragment类
android.app.Fragment // Android 3.0引入
android.support.v4.app.Fragment // 兼容3.0以下版本
2、重写Fragment的onCreateView()生命周期方法,并返回一个View
3、在布局文件中使用<fragment android:name="自定义Fragment的类路径" />
Fragment显示到页面上的方式:
显示步骤:
1. 创建Fragment的子类
在继承时,发现:在android.app包中和android.support.v4.app包中都有一个Fragment的类,那么该选取哪个类进行继承??
答: 如果想要在3.0以上的手机上运行本工程,就选取android.app包内的Fragment
如果想要在任意版本的手机上运行本工程,就选取android.support.v4.app包内的Fragment
2. 重写Fragment子类的onCreateView方法,通过onCreateView方法的返回值控制当前Fragment的显示内容
3. 显示Fragment
方式一: 在布局中设置要显示的Fragment
a. 在布局文件中添一个fragment(必须小写)标签
b. 添加必须要写的属性:
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name 用于设置Fragment子类的类完整路径
android:id或者android:tag属性,这两条属性均用于给Fragmenty设置唯一标识,
不同点在于:id属性设置的唯一标识为int类型
tag属性设置的唯一标识为String类型
注意:以上那些属性是必写的,其中id和tag属性可以不用两条全写,任选一条填写即可
否则:
如果不写android:name属性,抛出异常:
Cause By:NullPointerException:name==null
如果android:id或者android:tag属性都没写的话,抛出异常:
Cause By: IlleagArgumentException: must specify unique android:id or android:tag
方式二:通过代码添加要显示的Fragment
1. 在Activity的onCreate方法中通过setContentView指定要显示的布局
2. 在布局文件中添加一个任意的layout标签,并且给该标签指定id
3. 在Activity的onCreate方法中通过getFragmentManager()初始化一个FragmentManager对象
4. 通过manager对象调用
关于Fragment的版本适配:即关于android.support.v4.app包中的Fragment的使用方式
1. 关于在布局中设置要显示的Fragment不同处理的不同:
所有的处理都是一致的,只需将继承的Activity替换为FragmentActivity即可
2. 关于通过代码添加要显示的Fragment的不同:
a. 将继承的Activity替换为FragmentActivity
b. 将FragmentManager的初始化方法从getFragmentManager替换为getSupportFragmentManager方法
c. 其余处理方式完全一致
】
1.2.1 示例代码
【方式一: 在布局中设置要显示的Fragment
public class MyFragment1 extends Fragment {
/**
* 通过返回值控制当前要显示的布局文件所对应的View对象
*/
@Override
public View onCreateView(LayoutInflaterinflater, ViewGroup container,
BundlesavedInstanceState) {
// TODO Auto-generated method stub
Viewv = inflater.inflate(R.layout.frag1, null);
return v;
}
}
activity_main.xml
<!--android:name 用于设置Fragment子类的类完整路径
android:id或者android:tag属性,这两条属性均用于给Fragmenty设置唯一标识,
不同点在于:id属性设置的唯一标识为int类型
tag属性设置的唯一标识为String类型
-->
<fragment
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.xya.fragment.MyFragment1"
android:id="@+id/fragment1"
android:tag="fragment1"/>
public class MainActivity extends Activity {
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
【方式二:通过代码添加要显示的Fragment
activity_two.xml
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/framelayout"></FrameLayout>
/*
* 通过代码添加要显示的Fragment
*/
public class TwoActivity extendsActivity {
FragmentManager manager;
FragmentTransactionft;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
//1、初始化FragmentManager对象
manager = getFragmentManager();
//2、通过manager获得FragmentTransaction对象,因为只有此类中才有向页面中添加显示碎片的方法
ft=manager.beginTransaction();
//3、通过ft对象调用add或者replace方法向页面中添加显示的碎片
ft.add(R.id.framelayout, new MyFragment1(), "frag1");
//4、通过ft对象调用commit方法进行提交
ft.commit();
}
}
【
关于Fragment的版本适配:即关于android.support.v4.app包中的Fragment的使用方式
//.v4.app.Fragment
public class MyV4Fragment extendsFragment {
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroupcontainer, @Nullable Bundle savedInstanceState) {
// TODO Auto-generated method stub
View v = inflater.inflate(R.layout.frag1, null);
return v;
}
}
activity_three.xml
<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.xya.fragment.MyV4Fragment"
android:id="@+id/fragment1"/>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
></FrameLayout>
</LinearLayout>
public class ThreeActivity extends FragmentActivity {
@Override
protected voidonCreate(Bundle arg0) {
// TODO Auto-generated method stub
super.onCreate(arg0);
setContentView(R.layout.activity_three);
FragmentManagermanager = getSupportFragmentManager();
manager.beginTransaction().add(R.id.content,new MyV4Fragment()).commit();
}
}
】
1.3 Fragment基本使用的补充
【
1. 在通过代码添加Fragment的时候,使用FrameLayout与其余的Layout有什么区别??有什么优点??
区别:
a. 假设Fragment中设置的布局宽高以及布局控件中设置的宽高都设置match_parent,添加到FrameLayout中的Fragment可以实现match_parent的特点,但是添加到LinearLayout中的Fragment不行
b. 当通过add方法多次添加要显示的Fragemnt对象时,如果使用FrameLayout,那么多个Fragment对象之间是重叠覆盖效果,而LinearLayout是垂直或者水平排列效果
使用FrameLayout的优点:
比较容易实现Fragment对象宽高的match_parent效果
2. 通过在布局中添加显示Fragment与通过在代码中添加显示Fragment有没有什么区别??
通过在布局中添加fragment标签显示的Fragment对象永远无法被替换以及删除。
即使用原则为:
如果要显示在屏幕上的Fragment对象在整个的应用操作过程中,不需要被替换或删除,那么可以通过fragment标签控制显示。如果需要,通过add方法控制显示
3. 在FragmentTranslation对象调用add或replace等方法的时候,一定要commit过后才能看到效果。一旦commit过后想要再次调用add方法必须再次beginTranslation获取对象。否则抛出Caused by: java.lang.IllegalStateException: commit alreadycalled异常
4. FragmentTranslation对象的补充方法:
ft.remove() 删除参数中指定的Fragment对象
以下两点方法作用类似于android:visibility属性中的visible和invisible的效果
ft.show() 显示参数中指定的Fragment对象
ft.hide() 隐藏参数中指定的Fragment对象
以上3个方法使用时的注意事项:
a. 在调用show和hide控制显示和隐藏之前,必须确保要show或hide的Fragment已经通过add方法或者replace方法显示到屏幕上了
b. ft.remove()方法中指定Fragment对象与add方法中指定的对象必须是同一个,否则删除无效
如何在Fragment中处理网络数据的显示??
如果需要在Fragment中显示连网的数据的话,直接在Fragment
* 中启动异步任务,处理异步任务的接口回调即可
manager =getFragmentManager();
manager.beginTransaction().add(R.id.frameLayout_two, newTwoFragment()).commit();
manager.beginTransaction().replace(R.id.fl2,new TwoFragment()).commit();
public void click(View v){
switch (v.getId()) {
case R.id.but_add:
mf = newMyFragment();
manager.beginTransaction().add(R.id.framelayout_three, mf).commit();
break;
case R.id.but_remove:
manager.beginTransaction().remove(mf).commit();
break;
case R.id.but_show:
manager.beginTransaction().show(mf).commit();
break;
case R.id.but_hide:
manager.beginTransaction().hide(mf).commit();
break;
}
}
】
1.4 实现按钮+Fragment的切换效果
【
如何实现按钮+Fragment的切换效果??
通过RadioGroup控制按钮的显示及选中效果与非选中效果的图片切换
设置RadioGroup的onCheckChang监听,根据选中的RadioButton对象决定要replace替换显示哪个Fragment
注意:
1. 如果要设置Fragment中Button的点击事件,不要通过android:onclick属性进行设置
因为系统回到Activity的类中寻找方法
2. 实现替换效果时,不要通过add,而是通过replace,原因为:通过add方法添加n个Fragment显示到FrameLayout中的时候,n个Fragment是重叠覆盖的,但是被覆盖在下方的Fragment中的控件,默认仍接收点击事件,即使看不见被覆盖在下面的Fragment的显示。
如何在Fragment中控制控件的显示内容??
通过onCreaeView方法中要被返回的View对象调用findViewById寻找对应控件后,根据控件对象调用相应的set方法设置显示即可。
<RadioGroup
android:id="@+id/radioGroup1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radio0"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@null"
android:button="@null"
android:checked="true"
android:drawableTop="@drawable/slt_btn1_item"
android:gravity="center"
android:text="选项一" />
】