版本
Fragment,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6。
官方对于Fragment的定义:
Fragment是依赖于Activity的,不能独立存在的。
一个Activity里可以有多个Fragment。
一个Fragment可以被多个Activity重用。
Fragment有自己的生命周期,并能接收输入事件。
我们能在Activity运行时动态地添加或删除Fragment。
Fragment的优势有以下几点:
模块化(Modularity):我们不必把所有代码全部写在Activity中,而是把代码写在各自的Fragment中。
可重用(Reusability):多个Activity可以重用一个Fragment。
可适配(Adaptability):根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这样用户体验更好。
然后Fragment有静态和动态之分
1.静态Fragment
把Fragment放入布局文件直接调用,使用例子如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:layout_width="match_parent"
android:layout_height="100dp"
android:name="android.com.myapplication.ContentFragment"
android:id="@+id/fragment_content"/>
</RelativeLayout>
public class ContentFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,
Bundle savedInstanceState){
View view = inflater.inflate(R.layout.content,container,false);
return view;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button"
android:id="@+id/button"/>
</LinearLayout>
2 动态Fragment
关于动态Fragment就要涉及到Fragment的添加切换删除了
FragmentManager:管理和维护Fragment。(如果因为我们使用了support库的Fragment,因此需要使用getSupportFragmentManager()获取FragmentManager)
FragmentTransaction:对Fragment的添加、删除等操作都需要通过事务方式进行。
向FrameLayout布局里填充Fragment
FragmentTransaction add(@IdRes int containerViewId, Fragment fragment,
String tag);
使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体
FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment);
隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
transaction.hide(fragment)
显示Fragment
transaction.show(fragment)
FragmentManager拥有回退栈(BackStack),类似于Activity的任务栈,如果添加了该语句,就把该事务加入回退栈,当用户点击返回按钮,会回退该事务(回退指的是如果事务是add(frag1),那么回退操作就是remove(frag1));如果没添加该语句,用户点击返回按钮会直接销毁Activity。
addToBackStack("fname")
通过使用这些函数我们能够完成Fragment的切换,但是我们要知道,当我们add了一个Fragment,我们可能还会add同样的一个Fragment,这里我们就需要判断,去判断之前是否有添加这个Fragment,关于Fragment的分辨就引入tag,添加Fragment的时候同时赋予tag属性,下一次添加Fragment就要通过tag判断是否已有这个Fragment,如果有了就只需show这个Fragment。
因为replace会销毁Fragment对象,所以使用它不划算,要是下一次要用这个Fragment还要重新创建。
关于这个Fragment的动态切换,我写了比较规范的例子,可以参考
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button onebutton;
private Button twobutton;
private Fragment[] fmList = new Fragment[3];
private String[] fmTag = new String[3];
private int index = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onebutton = (Button)findViewById(R.id.onebutton);
twobutton = (Button)findViewById(R.id.twobutton);
onebutton.setOnClickListener(this);
twobutton.setOnClickListener(this);
fmList[1] = new OneFragment();
fmList[2] = new TwoFragment();
fmTag[1] = "one";
fmTag[2] = "two";
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.add(R.id.mycontent, fmList[1], fmTag[1]);
transaction.commit();
}
@Override
public void onClick(View v){
switch (v.getId()){
case R.id.onebutton:
if (index != 1) {
switchFragment(index, 1);
index = 1;
}
break;
case R.id.twobutton:
if (index != 2) {
switchFragment(index, 2);
index = 2;
}
break;
}
}
public void switchFragment (int one, int two) {
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
Fragment fm_one = fm.findFragmentByTag(fmTag[one]);
if (fm_one != null) {
transaction.hide(fm_one);
}
Fragment fm_two = fm.findFragmentByTag(fmTag[two]);
if (fm_two != null) {
transaction.show(fm_two);
} else if (fm_two == null) {
transaction.add(R.id.mycontent, fmList[two], fmTag[two]);
}
transaction.commit();
}
}
3 Fragment嵌套Fragment
Activity通过getSupportFragmentManager()获取FragmentManager,来管理Fragment
而Fragment里嵌套Fragment时,需要使用getChildFragmentManager()获取当前Fragment自己的FragmentManager管理Fm,
4.需要注意的地方
(1)在activity里嵌套Fragment,需要注意应用在后台时,因系统资源不够被系统清除应用资源,应用返回前台时activity生命周期会从onCreate再次开始,这个时候fragment会被重复添加
避免方法:
if(savedInstanceState==null){
toFragment()
}
(2)如果我们在一个Fragment执行完转场动画之前去执行Fragment事务,会使一个Fragment不可见
通过设置点击间隔来避免,或者不设置转场动画
//防止点击过快,快过动画执行时间
class ClickLmit(var time:Long){
var now:Long=0
fun click():Boolean{
if(System.currentTimeMillis()-now>time){
now=System.currentTimeMillis()
return true
}else {
return false
}
}
fun init(){
now=0
}
}