廢話不多說(shuō),直接上案例,以下案例截取自《Android編程權(quán)威指南第二版》第12章 對(duì)話框 12.3。
如圖1為CrimeFragment,圖2為點(diǎn)擊DETAILS下的第一個(gè)日歷按鈕彈出的日歷選擇器對(duì)話框,其為DatePickerFragment,這兩個(gè)fragment是托管在一個(gè)CrimeActivity上的,現(xiàn)在要實(shí)現(xiàn):
- 彈出的日歷選擇器要獲取并顯示按鈕上的日期信息
- 用戶在任意選擇日期并點(diǎn)擊OK后,按鈕可以展示用戶選擇的日期
功能1解決方案(傳遞數(shù)據(jù)給DatePickerFragment)
實(shí)現(xiàn)思路
在DatePickerFragment中新建newInstance(Date)方法,之后將Date作為argument附加給DatePickerFragment,然后在CrimeFragment中調(diào)用newInstance(Date)并將按鈕日期傳遞進(jìn)去,最后在DatePickerFragment中通過(guò)getArguments()方法獲取Date即可
代碼實(shí)現(xiàn)
- 添加newInstance(Date)方法
public class DatePickerFragment extends DialogFragment {
private static final String ARG_DATE = "date";
public static DatePickerFragment newInstances(Date date) {
Bundle args = new Bundle();
args.putSerializable(ARG_DATE, date); //ARG_DATE為標(biāo)記鍵key,目的是在get時(shí)找到對(duì)應(yīng)的值date
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArguments(args);
return fragment;
}
......
}
- 調(diào)用newInstance()方法并傳遞按鈕日期Date
public class CrimeFragment extends Fragment {
@Override
public View onCreateView(...) {
mDateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
DatePickerFragment dialog = DatePickerFragment.newInstances(mCrime.getDate());
dialog.show(fragmentManager, DIALOG_DATE);
}
}
}
}
- 在DatePickerFragment 中直接通過(guò)getArguments()方法獲取date。DatePickerFragment使用Date中的信息來(lái)初始化DatePicker對(duì)象,然而,DatePicker對(duì)象的初始化需整數(shù)形式的年月日。Date是個(gè)時(shí)間戳,無(wú)法直接提供整數(shù)形式的年月日。
要達(dá)到目的,必須首先創(chuàng)建一個(gè)Calendar對(duì)象,然后用Date對(duì)象配置它,再?gòu)腃alendar對(duì)象中取回所需信息。
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Date date = (Date) getArguments().getSerializable(ARG_DATE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_date, null);
mDatePicker = (DatePicker) v.findViewById(R.id.dialog_date_date_picker);
mDatePicker.init(year, month, day, null);
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok, null)
.create();
}
注:使用fragment的argument可以將接收來(lái)的數(shù)據(jù)保存在Bundle中,然后在使用時(shí)直接在fragment內(nèi)部取出即可,不需要依賴外部的activity或者fragment,這可以使fragment的封裝性更好,即低耦合,推薦使用。
功能2解決方案(返回?cái)?shù)據(jù)給CrimeFragment)
實(shí)現(xiàn)思路
- 類似于之前一篇Activity間的數(shù)據(jù)傳遞,通過(guò)設(shè)置目標(biāo)TargetFragment將兩個(gè)fragment關(guān)聯(lián),然后在DatePickerFragment中將所傳數(shù)據(jù)存入Intent,并借用目標(biāo)fragment的Fragment.onActivityResult()方法,就能實(shí)現(xiàn)數(shù)據(jù)回傳
代碼實(shí)現(xiàn)
- 設(shè)置CrimeFragment為目標(biāo)fragment
public class CrimeFragment extends Fragment {
private static final int REQUEST_DATE = 0;
@Override
public View onCreateView(...) {
mDateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
DatePickerFragment dialog = DatePickerFragment.newInstances(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE); //設(shè)置目標(biāo)fragment
dialog.show(fragmentManager, DIALOG_DATE);
}
}
}
}
REQUEST_DATE
為請(qǐng)求代碼,目標(biāo)fragment可以通過(guò)請(qǐng)求代碼確認(rèn)是哪個(gè)fragment在回傳數(shù)據(jù)
- 創(chuàng)建intent并將日期數(shù)據(jù)作為extra附加到intent,最后調(diào)用
CrimeFragment.onActivityResult(...)
傳遞數(shù)據(jù)給目標(biāo)fragment
public class DatePickerFragment extends DialogFragment {
public static final String EXTRA_DATE = "com.bignerdranch.android.criminalintent.date";
......
private void sendResult(int resultCode, Date date) {
if (getTargetFragment() == null) {
return;
}
Intent intent = new Intent();
intent.putExtra(EXTRA_DATE, date);
getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
}
- 使用
sendResult(...)
私有方法。用戶點(diǎn)擊對(duì)話框中的positive按鈕(即OK按鈕)時(shí),需要從日期選擇器DatePicker中獲取日期并回傳給CrimeFragment,在onCreateDailog(...)中,替換setPositiveButton(...)的null參數(shù),實(shí)現(xiàn)DialogInterface.OnClickListener監(jiān)聽(tīng)器接口。在監(jiān)聽(tīng)器接口中的onClick(...)方法中,獲取日期并調(diào)用setResult(...)
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
......
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int year = mDatePicker.getYear();
int month = mDatePicker.getMonth();
int day = mDatePicker.getDayOfMonth();
Date date = new GregorianCalendar(year, month, day).getTime();
sendResult(Activity.RESULT_OK, date);
}
})
.create();
}
- 在CrimeFragment中,覆蓋onActivityResult(...)方法,從extra中獲取日期數(shù)據(jù)并顯示
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
if (requestCode == REQUEST_DATE) {
Date date = (Date) data.getSerializableExtra(DatePickerFragment.EXTRA_DATE):
mCrime.setDate(date);
updateDate();
}
}
private void updateDate() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 EEEE", Locale.CHINA);
mDateButton.setText(dateFormat.format(mCrime.getDate()));
}
手機(jī)屏幕空間有限,常常使用activity托管全屏的fragment界面,以顯示用戶輸入要求。父Activity的fragment調(diào)用startActivityForResult()方法啟動(dòng)子Activity,子Activity銷毀后,會(huì)將數(shù)據(jù)通過(guò)onActivityResult()傳遞給父Activity,父Activity會(huì)接收到onActivityResult()的調(diào)用請(qǐng)求,requestCode和resultCode核對(duì)正確后,父Activity會(huì)接收并將數(shù)據(jù)轉(zhuǎn)發(fā)給自己托管的fragment
平板設(shè)備的屏幕空間比較大,適合以彈出對(duì)話框的方式顯示信息和接收用戶輸入。這種情況,應(yīng)設(shè)置目標(biāo)fragment并調(diào)用對(duì)話框fragment的show方法。對(duì)話框銷毀后,對(duì)話框的fragment會(huì)調(diào)用目標(biāo)fragment的onActivityResult方法。