- Fragment通过getActivity可以获取所在的activity,activity通过FragmentManager的findFragmentById获取Fragment
Fragment和activity是多对多的关系
fragment嵌入到activity中
A Fragment
public class AFragment extends Fragment {
private TextView mTvTitle;
@Nullable
@Override // 用来匹配xml文件
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_a,container,false);
return view;
}
@Override//等价于oncreated,在里边对fragment的控件进行设置
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTvTitle=view.findViewById(R.id.tv_title); //拿到R.id.tv_title
}
}
A xml
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="40sp"
android:layout_gravity="center"
android:text="我是AFragment"
android:gravity="center">
</TextView>
B Fragment
public class BFragment extends Fragment {
private TextView mTvTitle;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_b,container,false);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTvTitle=view.findViewById(R.id.tv_title2);
}
}
<TextView
android:id="@+id/tv_title2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="40sp"
android:layout_gravity="center"
android:text="我是BFragment"
android:gravity="center">
</TextView>
A和B基本一致,都是fragment匹配对应的xml,A中内容是"我是AFragment",B中内容是"我是BFragment"
现在有一个ContainerActivity将A装进去,然后通过按钮将A更换成B
Container xml
Button是change按钮
FrameLayout就是用来装fragment的,在activity中不设置暂时不会起作用
<Button
android:id="@+id/btn_change"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="更换Fragment"></Button>
<FrameLayout
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/btn_change"></FrameLayout>
ContainerActivity
需要引入AFragment和BFragment的实例
通过getFragmentManager将A添加到fl_container这个FrameLayout中
更换fragment:change按钮设置点击时间(为空实例化),使用replace方法将R.id.fl_container中fragment替换
private AFragment aFragment;
private BFragment bFragment;
private Button change;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_container);
//实例化AFragment
aFragment=new AFragment();
//AFragment添加到Activity中
getFragmentManager().beginTransaction().add(R.id.fl_container,aFragment).commitAllowingStateLoss();
change=findViewById(R.id.btn_change);
change.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(bFragment==null){
bFragment=new BFragment();
}
getFragmentManager().beginTransaction().replace(R.id.fl_container,bFragment).commitAllowingStateLoss();
}
});
}
getActivity 为null
fragment中有这个方法,是fragment与activity产生联系时会使用的一个方法,为了防止这个方法为空,将作为变量存起来
@Override
public void onAttach(Context context) {
super.onAttach(context);
ac= (Activity) context;
}
private Activity ac;
然后在onViewCreated做判断,为空 怎么样,不为空怎么样
@Override//等价于oncreated,在里边对fragment的控件进行设置
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if(ac==null){
}else{
}
}
当然,如果没有为空的风险,就不用这样做
activity传参给fragment
延续上面代码中场景
activity传递字符串给fragment,然后在activity中显示该fragment
静态方法,返回aFragment对象,并且通过该方法传参
public static AFragment newInstance(String title){
AFragment aFragment=new AFragment();
Bundle bundle=new Bundle();
bundle.putString("title",title);
aFragment.setArguments(bundle);
return aFragment;
}
实例化的时候调用该方法
//实例化AFragment
aFragment=AFragment.newInstance("参数");
Fragment回退栈
现在有这样一个场景:
ContainerActivity xml中有个FrameLayout,在activity中将AFragment加到该FrameLayout中
AFragment xml中有 tv_title(TextView:A) change(Button:将FrameLayout改为BFragment) changeT(Button:改变TextView里面值)
问题2:changeT改变TextView,当B返回到A后,虽然实例化还保存着(实例化的AFragment)但是页面视图被重置(activity传递的数据失效,即改变的TextView回到初始值),不使用replace方法,replace=remove+add,使用hide().add,就可以完整保留原来页面
操作如下
container
<FrameLayout
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</FrameLayout>
将AFragment放入 FrameLayout 这里add方法比之前多一个参数是Tag信息,后面hide方法会用到
//其中还用到了之前的给fragment传参的技术
public class ContainerActivity extends AppCompatActivity {
private AFragment aFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_container);
//实例化AFragment
aFragment=AFragment.newInstance("参数");
//AFragment添加到Activity中
getFragmentManager().beginTransaction().add(R.id.fl_container,aFragment,"a").commitAllowingStateLoss();
}
}
AFragment
AFragment xml
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="40sp"
android:layout_gravity="center"
android:text="A"
android:gravity="center">
</TextView>
<Button
android:id="@+id/btn_change"
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="30dp"
android:text="更换Fragment">
</Button>
<Button
android:id="@+id/btn_changeT"
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="30dp"
android:text="更换TextVFiew">
</Button>
AFragment.class
private TextView mTvTitle;
private Button change;
private BFragment bFragment;
private Button changeT;
public static AFragment newInstance(String title){
AFragment aFragment=new AFragment();
Bundle bundle=new Bundle();
bundle.putString("title",title);
aFragment.setArguments(bundle);
return aFragment;
}
@Nullable
@Override // 用来匹配xml文件
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_a,container,false);
return view;
}
@Override//等价于oncreated,在里边对fragment的控件进行设置
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mTvTitle=view.findViewById(R.id.tv_title); //拿到R.id.tv_title
if(getArguments()!=null){
mTvTitle.setText(getArguments().getString("title"));
}
change=view.findViewById(R.id.btn_change);
change.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(bFragment==null){
bFragment=new BFragment();
}
Fragment fragment=getFragmentManager().findFragmentByTag("a");
if(fragment!=null){
getFragmentManager().beginTransaction().hide(fragment).add(R.id.fl_container,bFragment).addToBackStack(null).commitAllowingStateLoss();
}else {
getFragmentManager().beginTransaction().replace(R.id.fl_container, bFragment).addToBackStack(null).commitAllowingStateLoss();
}
}
});
changeT=view.findViewById(R.id.btn_changeT);
changeT.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mTvTitle!=null){
mTvTitle.setText("新参数");
}
}
});
}
传参部分
mTvTitle=view.findViewById(R.id.tv_title); //拿到R.id.tv_title
if(getArguments()!=null){
mTvTitle.setText(getArguments().getString("title"));
}
改为BFragment,这里findFragmentByTag就是通过之前A设置的Tag来获取,如果它存在就使用hide,不存在也就不存在保留界面数据的问题,addToBackStack方法来使得返回时能够回退到原界面
change=view.findViewById(R.id.btn_change);
change.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(bFragment==null){
bFragment=new BFragment();
}
Fragment fragment=getFragmentManager().findFragmentByTag("a");
if(fragment!=null){
getFragmentManager().beginTransaction().hide(fragment).add(R.id.fl_container,bFragment).addToBackStack(null).commitAllowingStateLoss();
}else {
getFragmentManager().beginTransaction().replace(R.id.fl_container, bFragment).addToBackStack(null).commitAllowingStateLoss();
}
}
});
BFragment
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_title2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="40sp"
android:layout_gravity="center"
android:text="我是BFragment"
android:gravity="center">
</TextView>
</LinearLayout>
Fragment传递信息给Activity
首先container有一TextView,然后一个FrameLayout设为AFragment(里边有这么一个按钮)
通过接口回调实现
AFragment xml
<Button
android:id="@+id/btn_change"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="center"
android:text="更换数据"
android:textSize="30dp">
</Button>
AFragment
按钮和接口对象
private Button change;
private IOnMessageClick listener;
弄个接口
public interface IOnMessageClick{
void onClick(String text);
}
与activity产生联系时强转拿到该activity的接口,实现接口回调
@Override
public void onAttach(Context context) {
super.onAttach(context);
try{
listener=(IOnMessageClick)context;//当与activity建立联系时,将它的该接口传进来
}catch (ClassCastException e){
throw new ClassCastException("activity中 未实现onclick方法");
}
}
回调该接口传参
@Override//等价于oncreated,在里边对fragment的控件进行设置
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
change=view.findViewById(R.id.btn_change);
change.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击更换数据按钮,从fragment将activity中的数据改变
listener.onClick("数据已改变");
}
});
}
Activity
让activity实现这个接口
@Override
public void onClick(String text) {
mTvTitle=findViewById(R.id.tv_title);
mTvTitle.setText(text);
}