Fragment
- 一个Activity可有多个fragment,fragment不能脱离Activity而存在; Activity是屏幕的主体,而fragment是Activity的一个组成元素。
- 有两种方式通过Activity加载fragment,动态和静态方法
静态加载fragment
在布局文件中写出fragment的布局,并且绑定一个fragment文件,通过一个Activity加载这个fragment,在activity中写入fragment,就可以显示出fragment的界面。
案例:
点击MainActivity中的字符,跳转到staticFragmentActivity,staticFragmentActivity加载出fragment。这个fragment是事先写好的,直接通过Activity就可以显示出来。
MainActivity的界面:
显示fragment的内容:
代码在通过staticFragmentActivity加载出fragment,我们在staticFragmentActivity的布局文件中加载了两个fragment,都是一样的内容:
最终的效果图为:
接下来我们看代码:
首先通过MainActivity跳转到staticFragmentActivity。
package com.example.apple.fragment;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//静态加载
startActivity(new Intent(MainActivity.this,StaticFragmentActivity.class));
}
});
}
}
接下来我们写出fragment及其布局文件,将二者绑定,注意fragment有多个生命周期,最主要的是onCreateView,在这个方法里面绑定布局
package com.example.apple.fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Created by apple on 2018/5/12.
*/ //创建列表fragemnt
public class listFragment extends Fragment {
//fragemnt有多个生命周期
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
//创建视图,最主要的生命周期
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);//是否绑定,因为已经绑定,所以false
TextView textView=view.findViewById(R.id.textView1);
return view;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onDetach() {
super.onDetach();
}
}
我们在通过staticFragmentActivity加载出fragment
package com.example.apple.fragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class StaticFragmentActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_static_fragment);
}
}
StaticFragmentActivity的布局文件里引入fragment
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#eab6b6"
>
<fragment
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/listFragment"
android:layout_centerInParent="true"
android:name="com.example.apple.fragment.listFragment"/>
<fragment
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/listFragment2"
android:layout_alignParentBottom="true"
android:name="com.example.apple.fragment.listFragment"/>
</RelativeLayout>
fragment的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#77b2e2">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:id="@+id/textView1"
android:textColor="#e7bfbf"
android:textSize="20sp"
android:text="text1"
android:gravity="center"
/>
</RelativeLayout>
好了大功告成。
动态加载fragment
1.即通过代码实现activity加载fragment。首先我们还是要写出fragment的布局,并且写出fragment的容器,容器是用来放置fragment的。我们在MainActivity的布局中写了两个平行的放置fragment的容器。id分别为“listContainer”和“listContainer2”。
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="150dp"
android:layout_height="match_parent"
android:id="@+id/listContainer"
android:orientation="vertical"
android:layout_margin="1dp"
>
</LinearLayout>
<LinearLayout
android:layout_width="200dp"
android:layout_height="match_parent"
android:id="@+id/listContainer2"
android:orientation="vertical"
android:layout_margin="1dp">
</LinearLayout>
</LinearLayout>
2.在MainActivity中,动态加载fragment,让fragment的内容显示在Main Activity的两个平行布局中。getSupportFragmentManager()是属于framgnetActivity的方法,而AppCompatActivity继承自fragmentActivity。
在add方法中,第一个参数是fragment放置容器的id,第二个参数是fragment,注意fragment在每次添加都要new一次,或者提前建立好,并且不能传入同一个fragment对象,否则报错:
Caused by: java.lang.IllegalStateException: Can't change container ID of fragment listFragment{27152b2 id=0x7f07003c}: was 2131165244 now 2131165245
代码为:
getSupportFragmentManager()
.beginTransaction()//开启事务
.add(R.id.listContainer,new listFragment())//将fragment布局放在listContainer中
.commit();//提交
getSupportFragmentManager()
.beginTransaction()
.add(R.id.listContainer2,new listFragment())
.commit();
我们看一下显示效果:
3.除了动态的添加fragment碎片,我们也能删除碎片(remove)或者更改碎片(replace)
首先我们remove左边的碎片:
因为remove方法传入的参数是fragment,我们指定删除左边的,所以要对代码进行修改,新建一个fragment对象,在add到左边的布局
listFragment listFragment=new listFragment();
getSupportFragmentManager()
.beginTransaction()//开启事务
.add(R.id.listContainer,listFragment)//将fragment布局放在listContainer中
.commit();//提交
getSupportFragmentManager()
.beginTransaction()
.remove(listFragment)
.commit();
显示效果为:
同样,我们也能修改碎片,在左右两边碎片都同时存在的基础上,我们对右边的碎片进行修改。这里我们新建一个fragment,并且将布局文件与fragment绑定。将右边的fragment替换。
新的fragment的布局文件:
<?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"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello"
android:textSize="40sp"
android:textColor="#ef4c4c"/>
</LinearLayout>
替换fragment:
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.listContainer2,new listFragment2())
.commit();
结果为:
4.我们也可以在activity和fragment之间进行传值,包括activity向fragment传值,fragment向activity传值,framgent向fragment传值。
activity向fragment传值
这里我们使用bundle传值。
public static final String BUNDLE_TITLE = "bundle_title";//提取成静态常量
public static listFragment newInstance(String title){
listFragment listFragment=new listFragment();
Bundle bundle=new Bundle();
bundle.putString(BUNDLE_TITLE,title);//将数据传递给bundle,在把bundle当作arguments传给fragment,最后返回fragment
listFragment.setArguments(bundle);
return listFragment;
}
再通过fragment的onCreate方法获取argument的值
private String mTitle=null;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getArguments()!=null){
mTitle=getArguments().getString(BUNDLE_TITLE);//提取成全局变量,
}
}
在初始化fragment时并对text初始化,赋值
View view = inflater.inflate(R.layout.fragment_list, container, false);//是否绑定,因为已经绑定,所以false
TextView textView=view.findViewById(R.id.textView1);
textView.setText(mTitle);
最后在MainActivity中通过代码设置framgent里面的text值
getSupportFragmentManager()
.beginTransaction()//开启事务
.add(R.id.listContainer,listFragment.newInstance("list1"))//将fragment布局放在listContainer中
.commit();//提交
getSupportFragmentManager()
.beginTransaction()
.add(R.id.listContainer2,listFragment.newInstance("listlist2"))
.commit();
结果显示为
以上便是activity向fragment传值。
fragment向activity传值
这里我们使用回调的方法,即Callback。我们使用接口回调。
我们点击fragments里面的text如list1,listlist2就可以改变activity的内容,比如说在界面里显示的fragment的项目名。activity接收了fragment的传入的值后,就将名称改变。
首先我们在fragment文件里定义一个点击事件的接口:
//1.定义接口
public interface onTitleCLickListener{
void onClick(String title);
}
接下来是定义接口的全局变量
//2。定义全局变量
private onTitleCLickListener mOnTitleCLickListener;
第三步是设置接口的方法(类似于点击事件调用接口)
//3。设置接口的方法
public void setOnTitleCLickListener(onTitleCLickListener onTitleCLickListener) {
mOnTitleCLickListener = onTitleCLickListener;
}
因为我们是对text设置点击事件,所以textView要设置监听事件,调用onClick方法,点击后就可以调用mOnTitleCLickListener的点击事件,把fragment的值传递给activity
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mOnTitleCLickListener!=null){
mOnTitleCLickListener.onClick(mTitle);
}
}
});
在MainActivity里面,对mOnTitleCLickListener的onClick方法进行定义
即改变activity的title值
@Override
public void onClick(String title) {
setTitle(title);//点击fragment,将值回调给activity并且改变activity的名字
}
最后加载每一个fragment,设置text的值并设置点击事件
listFragment listFragment= com.example.apple.fragment.listFragment.newInstance("list1");
getSupportFragmentManager()
.beginTransaction()//开启事务
.add(R.id.listContainer,listFragment)//将fragment布局放在listContainer中
.commit();//提交
listFragment.setOnTitleCLickListener(this);
listFragment listFragment2= com.example.apple.fragment.listFragment.newInstance("list2");
getSupportFragmentManager()
.beginTransaction()
.add(R.id.listContainer2,listFragment2)
.commit();
listFragment2.setOnTitleCLickListener(this);
效果图为:(这是点击左边的效果)