一、前提
Fragment作为Android最基本,最重要的基础概念之一,在开发中经常会和他打交道。Fragment有自己的生命周期,依赖于Activity,可以与Activity的相互获取(Fragment通过getActivity()获取Activity;Activity通过FragmentManger的findFragmentById()或findFragmentByTag()获取Fragment),与Activity的多对多关系
二、目标
Fragment
三、内容
1、Fragment在Activity中的基本运行
先在activity_main中添加如下布局文件,一个按钮和一个布局管理器
分别建立两个新的java文件,且其中的代码相同,这里展示一个
在xml文件中添加一个TextView
在java文件中添加
package com.example.sunny.fragment;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Created by Sunny on 2020/4/24.
*/
public class BFragment extends Fragment {
private TextView textView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragmentb,container,false);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
textView= (TextView) view.findViewById(R.id.tv);
}
}
在此处我们可以看到java文件继承Fragment
且常用的两种方法是:
onCreateView()方法,该方法返回视图文件,相当于Activity中onCreate方法中setContentView一样
onViewCreated()方法,该方法当view创建完成之后的回调方法
说白了就是一个用于创造,一个用于运用
在onCreateView()中首先还是找到为它写的布局文件,返回视图文件
在onViewCreated()中找到其视图文件中的各类控件进行使用
在MainActivity中添加
package com.example.sunny.fragment;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private AFragment aFragment;
private BFragment bFragment;
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button= (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (bFragment == null) {
bFragment = new BFragment();
}
//返回FragmentManager,用于与与此活动关联的片段进行交互;;在与这个片段管理器关联的片段上启动一系列编辑操作
getFragmentManager().beginTransaction().replace(R.id.fl, bFragment).commitAllowingStateLoss();
}
});
//实例化AFragment
//aFragment=AFragment.newInstance("hello");
aFragment=new AFragment();
//把AFragment添加到Activity中,记得调用commit
getFragmentManager().beginTransaction().add(R.id.fl,aFragment).commitAllowingStateLoss();
}
逻辑就是:首先实例化一个Fragment,将Fragment添加到Activity中,通过按钮点击跳转至另一个Fragment
getFragmentManager().beginTransaction()是固定操作,关键在于你是想要替换还是添加,都是将fragment的实例传给之前布局的LinearLayout中,最后提交,一般使用commitAllowingStateLoss()方法进行提交因为commmit()方法有时会报错
2、向Fragment传递参数
在AFragment中添加一个静态方法,在该方法中进行实例化并且返回fragment
setArguments()方法:为这个片段提供构造参数。这只能在片段被连接到它的活动之前调用;也就是说,您应该在构建片段之后立即调用它。这里提供的参数将在片段销毁和创建之间保留。
public static AFragment newInstance(String title){
AFragment fragment=new AFragment();
Bundle bundle=new Bundle();
bundle.putString("title",title);
fragment.setArguments(bundle);
return fragment;
}
在onViewCreated()方法中添加,判断之前创建的是否存在,若存在则可赋值
if(getArguments()!=null){
textView.setText(getArguments().getString("title"));
}
最后在MainActivity中将之前实例化的语句改为
aFragment=AFragment.newInstance("hello");
3、Fragment回退栈
首先要对代码进行改动,去掉activity_main中的按钮,将它放置在AFragment的布局文件中,并且在添加一个按钮
在MainActivity中删除Button的点击事件,添加一个标记
package com.example.sunny.fragment;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private AFragment aFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化AFragment
aFragment=AFragment.newInstance("hello");
//把AFragment添加到Activity中,记得调用commit
getFragmentManager().beginTransaction().add(R.id.fl,aFragment,"a").commitAllowingStateLoss();
}
}
注意:多了的那个"a"表示一个标记,可使用它来找寻相应的片段
在AFragment的java文件中的onViewCreated()中添加
button1.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, bFragment).addToBackStack(null).commitAllowingStateLoss();
}else{
getFragmentManager().beginTransaction().replace(R.id.fl, bFragment).addToBackStack(null).commitAllowingStateLoss();
}
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText("new text");
}
});
第一个按钮的作用是点击后调到下一个Fragment中,首先判断是否存在bFragment,若不存在则实例化一个,若存在,则先找是否发现标记a,若标记a的片段存在,则将它隐藏后添加新的Fragment,若不存在,则直接进行替换
addToBackStack(null)是将此事务添加到后堆栈。这意味着事务将在提交后被记住,并将在稍后弹出堆栈时反转其操作。他其中的参数是一个String name表示此回堆栈状态的可选名称,或null;一般写null;意思也就是说,添加这个方法后,你使用返回键后就会返回你的上一步操作,否则会直接回到你的首次操作,比如你有一个主页面,点击按钮后疯狂跳转,如果没有添加此方法,则点击返回键直接返回主页面,中间所有的跳转页面都不会再显示
hide()表示隐藏现有的片段。这只与那些视图已被添加到容器中的片段相关,因为这将导致视图被隐藏。这样你即使点击修改文字后,再进入BFragment后,返回看到的还是修改后的文字否则。你不管怎样更改文字内容,更换Fragment后返回看到的永远都是最初的文字,如下图
第二个按钮的作用是点击后文字改变,整个的效果
4、二者之间的通信
Fragment发送一个消息给Activity,让他去执行,利用回调接口的方法
先在AFragment的xml文件中在添加一个按钮
在AFragment的中写一个接口
private IOnMessageClick listener;
public interface IOnMessageClick{
void onClick(String text);
}
在MainActivity中实现这个接口,并且重写方法
package com.example.sunny.fragment;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements AFragment.IOnMessageClick{
private AFragment aFragment;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView= (TextView) findViewById(R.id.title);
//实例化AFragment
aFragment=AFragment.newInstance("hello");
//aFragment=new AFragment();
//把AFragment添加到Activity中,记得调用commit
getFragmentManager().beginTransaction().add(R.id.fl,aFragment,"a").commitAllowingStateLoss();
}
@Override
public void onClick(String text) {
textView.setText(text);
}
}
在AFragment中,当Fragment依附于Activity时有一个方法,是onAttach(),表示当片段首次附加到其上下文时调用。
@Override
public void onAttach(Context context) {
super.onAttach(context);
try{
listener= (IOnMessageClick) context;
}catch(ClassCastException e){
e.printStackTrace();
}
}
最后在新的按钮的点击事件中添加代码
listener.onClick("succeed");
四、总结
Fragment相对来说功能强大,与Activity相辅相成,很重要的一个知识点,也比较复杂