上一节简单实现了Fragment的动态使用,但是还有很多细节没有提及,这一节我们把一些常用的细节说说一说。
上一节里我们可以实现Fragment之间跳转,但是我们需要在跳转的同时传递参数,要怎么办呢?不要着急,Google的工程师也想到了,所以提供了解决方法。
Fragment有个叫做setArguments(Bundle)
的方法,用来传递参数;我们可以通过Bundle
,添加我们需要的参数,然后再Fragment里使用getArguments()
获取。
比如:
Fragment2 fragment2 = new Fragment2();
Bundle bundle = new Bundle();
bundle.putString("aaa","bbbb");
fragment2.setArguments(bundle);
然后我们在Fragment里面可以在onCreate()
里面获取这些参数:
Bundle bundle = getArguments();
String v = bundle.getString("aaa");
在官网上,提供了demo,使用的是静态方法。下面我们通过两个Fragment,来展示一下用法。
第一个Fragment,我们叫做FragmentOne;第二个Fragment我们叫做FragmentTwo,我们需要从FragmentOne传递参数到FragmentTwo.
FragmentOne:
public class FragmentOne extends Fragment {
public static final String ARGUMENT_KEY = "ARGUMENT_KEY";
private View rootView;
private Button btnJump2FragmentTwo;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_layout_one, container, false);
btnJump2FragmentTwo = (Button) rootView.findViewById(R.id.btn_jump_2_fragment_two);
btnJump2FragmentTwo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString(ARGUMENT_KEY,"这个是从FragmentOne传递给FragmentTwo的参数");
FragmentTwo fragmentTwo = FragmentTwo.getFragmentTwo(bundle);
getFragmentManager().beginTransaction().add(R.id.ft_container,fragmentTwo).commit();
}
});
return rootView;
}
}
FragmentTwo:
public class FragmentTwo extends Fragment {
public static FragmentTwo getFragmentTwo(Bundle argumentBundle) {
FragmentTwo fragmentTwo = new FragmentTwo();
fragmentTwo.setArguments(argumentBundle);
return fragmentTwo;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if (bundle != null) {
String argument = bundle.getString(FragmentOne.ARGUMENT_KEY);
LogUtils.e(argument);
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_layout_two,container,false);
}
}
在FragmentTwo里面,我们获取到参数后,只打印了一下。
在Fragment里打开一个新的Activity的方式跟Activity之间的跳转一样都是使用startActivity()
这个方法;如果需要传递返回值,需要startActivityForResult()
和onActivityResult
配合使用;如果启动了一个新的Activity里面有一个Fragment,需要在Fragment里面执行 setResult(),但是Fragment里不提供这个方法,要如何办呢?我们可以使用 getActivity().setResult()
。
关于这些内容就不再代码演示了,跟Activity几乎一模一样,大家就按着Activity的实现方式实现就OK了。
官网提供的方式是使用接口回调。
我们首先创建一个Fragment,并且定义一个回调接口,用来在Activity中回调。
public class BlankFragment extends Fragment {
//定义一个回调接口
private OnFragmentInteractionListener mListener;
public BlankFragment() {
}
public static BlankFragment newInstance(Bundle arg) {
BlankFragment fragment = new BlankFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
Bundle args = getArguments();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank, container, false);
Button button = (Button) view.findViewById(R.id.btn_change_text);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//将下面的这些文字传递给Activity
onButtonPressed("我要修改Activity中的文字");
}
});
return view;
}
public void onButtonPressed(String text) {
if (mListener != null) {
mListener.onFragmentInteraction(text);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* 回调的接口,需要在Activity中实现,当我们的Fragment有操作时,会通过里面的方法通知到Activity
*/
public interface OnFragmentInteractionListener {
//通知到Activity Fragment 有操作,并且将需要的参数传递给Activity
void onFragmentInteraction(String text);
}
}
在Activity中就简单多了,只需要继承Fragment中实现的接口,并将Fragment显示到界面,就Ok了。
public class BlankActivity extends AppCompatActivity implements BlankFragment.OnFragmentInteractionListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blank);
//获取Fragment的实例,这里我们不需要传递参数
BlankFragment fragment = BlankFragment.newInstance(null);
//将Fragment加入到Activity中
getFragmentManager().beginTransaction().add(R.id.ft_container, fragment).commit();
}
@Override
public void onFragmentInteraction(String text) {
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(text);
}
}
当我们点击Fragment中的按钮时,Activity中TextView的文字就会发生改变:
仅仅从字面上,就知道这是一个类似对话框的Fragment,它可以很容易的实现自定义对话框;当然它还依然是一个Fragment,跟其它的Fragment有一样的生命周期,只是它被封装成了一个专门显示Dialog的Fragment。它没有自己的界面,这需要我们继承它,然后重写它的onCreateView()
方法,然后自定义界面就OK。下面我来看代码:
首先我写一下布局:
然后对应的,我们创建一个DialogFragment的子类:
public class MyDialogFragment extends DialogFragment implements View.OnClickListener {
private View rootView;
private TestActivity mActivity;
//在Fragment附着在Activity上时,获取要附着的Activity实例。
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = (TestActivity) activity;
}
//创建Fragment 实例
public static MyDialogFragment newInstance(String arg) {
MyDialogFragment f = new MyDialogFragment();
Bundle args = new Bundle();
args.putString("arg", arg);
f.setArguments(args);
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_my_dialog, container, false);
initViews();
return rootView;
}
private void initViews() {
rootView.findViewById(R.id.btnOk).setOnClickListener(this);
rootView.findViewById(R.id.btnCancel).setOnClickListener(this);
}
//监听Dialog消失
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
Toast.makeText(getActivity(), "Dialog Dismiss", Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnOk:
//通过Activity的实例来调用Dialog消失的方法
mActivity.dismissDialog();
Toast.makeText(getActivity(), "Dialog OK", Toast.LENGTH_SHORT).show();
break;
case R.id.btnCancel:
//取消Dialog的显示,使用返回键也可以达到同样的结果
mActivity.dismissDialog();
Toast.makeText(getActivity(), "Dialog Cancel", Toast.LENGTH_SHORT).show();
break;
}
}
}
最后我们把DialogFragment显示出来。
public class TestActivity extends AppCompatActivity {
MyDialogFragment mDialogFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mDialogFragment = MyDialogFragment.newInstance(null);
}
public void showDialog(View view) {
//点击按钮时,显示Dialog
mDialogFragment.show(getFragmentManager(), "dialog");
}
//Dialog 消失
public void dismissDialog(){
mDialogFragment.dismiss();
}
}
如果不想自己去定义界面,也可以在 DialogFragment
里面实现Android自带的AlertDialog效果,我们只需要在重写DialogFragment
的onCreateDialog()
,然后在里面是实现AlertDialog就OK了。
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("标题");
builder.setMessage("消息提示!!!");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getActivity(),"确定",Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getActivity(),"取消",Toast.LENGTH_SHORT).show();
}
});
return builder.create();
}
这个Fragment里面封装了一个ListView,我们只需要是 setListAdapter
方法,给ListView设置一个Adapter就OK。
public class MyListFragment extends ListFragment {
private List mList;
public MyListFragment() {
mList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
mList.add("Title = " + i);
}
}
//创建Fragment 实例
public static MyListFragment newInstance(String arg) {
MyListFragment f = new MyListFragment();
Bundle args = new Bundle();
args.putString("arg", arg);
f.setArguments(args);
return f;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ArrayAdapter adapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, mList);
setListAdapter(adapter);
}
}
当然如果我们需要行点击事件,可以重写它的onListItemClick
方法即可:
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(getActivity(), "点击的是第" + position + "项", Toast.LENGTH_SHORT).show();
}
其它还有 PreferenceFragment
和WebViewFragment
,这里就不再一一介绍了,大家有兴趣可以研究一下。