java 在 OnClickListener 中实现 DialogFragment 接口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28620026/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implement DialogFragment interface in OnClickListener
提问by tymm
I need to build a DialogFragment which returns user input from the dialog to an activity.
The dialog needs to be called in an OnClickListener which gets called when an element in a listview gets clicked.
The return value of the DialogFragment (the input of the user) should be directly available in the OnClickListener in the activity.
我需要构建一个 DialogFragment,它将用户输入从对话框返回到活动。该对话框需要在 OnClickListener 中调用,当单击列表视图中的元素时调用该监听器。
DialogFragment 的返回值(用户的输入)应该在活动的 OnClickListener 中直接可用。
I tried to implement this by sticking to the official docs: http://developer.android.com/guide/topics/ui/dialogs.html#PassingEvents
我试图通过坚持官方文档来实现这一点:http: //developer.android.com/guide/topics/ui/dialogs.html#PassingEvents
I need something like the following which doesn't work since I don't know how to make the anonymous OnClickListener implement the interface of the CustomNumberPicker class.
As far as I know implementing the interface is necessary in order to get data from the DialogFragment back to the Activity.
我需要类似以下的东西,但它不起作用,因为我不知道如何让匿名 OnClickListener 实现 CustomNumberPicker 类的接口。
据我所知,为了将 DialogFragment 中的数据返回到 Activity,实现该接口是必要的。
Main Activity:
主要活动:
public class MainAcitivity extends ActionBarActivity {
[...]
// ArrayAdapter of the Listview
private class ListViewArrayAdapter extends ArrayAdapter<Exercise> {
public ListViewArrayAdapter(Context context, ArrayList<Exercise> exercises) {
super(context, 0, exercises);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
[...]
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_workoutdetail, parent, false);
}
TextView tvSets = (TextView) convertView.findViewById(R.id.tvWorkoutExerciseSets);
tvSets.setText(sets.toString());
// OnClickListener for every element in the ListView
tvSets.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// This is where the Dialog should be called and
// the user input from the Dialog should be returned
DialogFragment numberpicker = new CustomNumberPicker();
numberpicker.show(MainActivity.this.getSupportFragmentManager(), "NoticeDialogFragment");
}
// Here I would like to implement the interface of CustomNumberPicker
// in order to get the user input entered in the Dialog
});
return convertView;
}
}
}
CustomNumberPicker (basically the same as in the docs):
CustomNumberPicker(与文档中基本相同):
public class CustomNumberPicker extends DialogFragment {
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
// Use this instance of the interface to deliver action events
NoticeDialogListener mListener;
// Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Verify that the host activity implements the callback interface
try {
// Instantiate the NoticeDialogListener so we can send events to the host
mListener = (NoticeDialogListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Sets")
.setPositiveButton("set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Return stuff here to the activity?
}
})
.setNegativeButton("cancle", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
采纳答案by Droidekas
Something like this?
像这样的东西?
public class CustomNumberPicker extends DialogFragment {
private NoticeDialogListener ndl;
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
//add a custom constructor so that you have an initialised NoticeDialogListener
public CustomNumberPicker(NoticeDialogListener ndl){
super();
this.ndl=ndl;
}
//make sure you maintain an empty constructor
public CustomNumberPicker( ){
super();
}
// Use this instance of the interface to deliver action events
NoticeDialogListener mListener;
// Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//remove the check that verfis if your activity has the DialogListener Attached because you want to attach it into your list view onClick()
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Sets")
.setPositiveButton("set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ndl.onDialogPositiveClick(dialog);
}
})
.setNegativeButton("cancle", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ndl.onDialogNegativeClick(dialog);
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
and then your listView onClick becomes:
然后你的 listView onClick 变成:
tvSets.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// This is where the Dialog should be called and
// the user input from the Dialog should be returned
//
//
DialogFragment numberpicker = new CustomNumberPicker(new NoticeDialogListener() {
@Override
public void onDialogPositiveClick(DialogFragment dialog) {
//What you want to do incase of positive click
}
@Override
public void onDialogNegativeClick(DialogFragment dialog) {
//What you want to do incase of negative click
}
};);
numberpicker.show(MainActivity.this.getSupportFragmentManager(), "NoticeDialogFragment");
}
// Here I would like to implement the interface of CustomNumberPicker
// in order to get the user input entered in the Dialog
});
Do read the comments I have added.And it can even be further optimized because you really dont need an entire dialog instance to get the values you need.
请阅读我添加的评论。它甚至可以进一步优化,因为您确实不需要整个对话框实例来获取您需要的值。
EDITa possible optimization could be:
编辑一个可能的优化可能是:
Changing the Listener interface to :
将监听器接口更改为:
public interface NoticeDialogListener {
public void onDialogPositiveClick(String output);
public void onDialogNegativeClick(String output);
//or whatever form of output that you want
}
Then modify the implemented methods accordingly.
然后相应地修改实现的方法。
回答by Avsector
You should have your activity, implement your interface (NoticeDialogListener
).
你应该有你的活动,实现你的接口 ( NoticeDialogListener
)。
public class MainActivity extends ActionBarActivity implements
NoticeDialogListener{
@Override
public void onDialogPositiveClick(DialogFragment dialog){
//Do something
}
@Override
public void onDialogNegativeClick(DialogFragment dialog){
//Do some other things
}
[...]
}
Then in your button click listeners of the dialog, you use the mListener
and call the methods, which is now implemented in the activity and the code will be executed there.
然后在对话框的按钮单击侦听器中,使用mListener
和 调用方法,该方法现在在活动中实现,代码将在那里执行。
builder.setMessage("Sets")
.setPositiveButton("set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if(mListener != null)
mListener.onDialogPositiveClick(CustomNumberPicker.this);
}
});
Also note that you should set the mListener
to null in the onDetach()
method of your DialogFragment.
另请注意,您应该mListener
在onDetach()
DialogFragment的方法中将设置为 null 。
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
回答by user2288580
Here's how it's done: In the Activity where you show the DiaogFragment, set the arguments of the DialogFragment with the desired name value pair. Also make sure that the activity implements the DialogInterface.OnClickListener In the overridded onClick pick up the value from the aforementioned name value pair
操作方法如下:在显示 DiaogFragment 的活动中,使用所需的名称值对设置 DialogFragment 的参数。还要确保活动实现了 DialogInterface.OnClickListener 在覆盖的 onClick 中从上述名称值对中获取值
public class MainActivity extends AppCompatActivity implements DialogInterface.OnClickListener {
private static SettingsFragment settingsFragment;
private Button btnSettings;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
btnSettings = (Button) findViewById(R.id.btnSettings);
btnSettings.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
settingsFragment = new SettingsFragment();
Bundle bundle = new Bundle();
bundle.putString("myKey", null);
settingsFragment.setArguments(bundle);
//Use the commented out line below if you want the click listener to return to a fragment instead of an activity
//assuming that this class in a fragment and not an activity
//rotateSettingsFragment.setTargetFragment(getActivity().getSupportFragmentManager().findFragmentByTag("TagForThisFragment"), 0);
settingsFragment.setTargetFragment(settingsFragment, 0);
settingsFragment.setCancelable(true);
settingsFragment.show(getSupportFragmentManager(), "SettingsFragment");
}
});
}
@Override
public void onClick(DialogInterface dialog, int which) {
if(getResources().getResourceEntryName(which).equals("btnSettingFragmentClose")) {
String myValue = settingsFragment.getArguments().getString("myKey");
dialog.dismiss();
}
}
}
In your DialogFragment declare a DialogInterface.OnClickListener and cast it to the activity in the onAttach. In the event that needs to send back the data to the activity; set the buddle arguments and then call the onClickListener.onClick
在您的 DialogFragment 中声明一个 DialogInterface.OnClickListener 并将其转换为 onAttach 中的活动。在需要将数据发回给活动的情况下;设置 buddle 参数,然后调用 onClickListener.onClick
public class SettingsFragment extends DialogFragment {
公共类 SettingsFragment 扩展 DialogFragment {
private View rootView;
private Button btnSettingFragmentClose;
private DialogInterface.OnClickListener onClickListener;
public SettingsFragment() {}
/* Uncomment this and comment out on onAttach when you want to return to a fragment instead of an activity.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onClickListener = (DialogInterface.OnClickListener) getTargetFragment();
}
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_settings, container, false);
btnSettingFragmentClose = (Button) rootView.findViewById(R.id.btnSettingFragmentClose);
btnSettingFragmentClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getArguments().putString("myKey", "Hello World!");
onClickListener.onClick(getDialog(), v.getId());
}
});
return rootView;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
onClickListener = (DialogInterface.OnClickListener) activity;
}
catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement mainFragmentCallback");
}
}
}
}
回答by Antonio Cord
This simple solution works for me:
这个简单的解决方案对我有用:
public class MyActivity implements MyDialogFragment.Listener {
// ...
@Override
public void onMyEvent() {
// do something here
}
}
public class MyDialogFragment extends DialogFragment {
private Listener mCallback;
public interface Listener {
void onMyEvent();
}
@SuppressLint("RestrictedApi")
@Override
public void setupDialog(final Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.dialog_fragment_custom, null);
dialog.setContentView(contentView);
mCallback = (Listener) getActivity();
Button myBtn = (Button) dialog.findViewById(R.id.btn_custom);
myBtn.setOnClickListener(v -> {
mCallback.onMyEvent();
dismiss();
});
}
}
回答by Nikolay Nikiforchuk
As an example you can use DatePickerDialogwhere DatePickerDialog.OnDateSetListenerused to deliver result.
例如,您可以使用DatePickerDialog,其中DatePickerDialog.OnDateSetListener用于传递结果。
or this is one of my implementations that allow to keep dialog screen open until user not finished with some action or not entered valid data. With custom callback that provide exact interface to this dialog.
或者这是我的实现之一,它允许保持对话框屏幕打开,直到用户未完成某些操作或未输入有效数据。使用自定义回调为该对话框提供准确的接口。
public class ConfirmPasswordDialog extends DialogFragment {
private OnPaswordCheckResult resultListener;
private TextView passwordView;
public ConfirmPasswordDialog(OnPaswordCheckResult resultListener){
this.resultListener = resultListener;
}
@Override
public android.app.Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_layout, null);
builder.setView(dialogView);
passwordView = (TextView) dialogView.findViewById(R.id.password);
passwordView.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {/*do nothing*/}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {/*do nothing*/}
@Override
public void afterTextChanged(Editable s) {
if(passwordView != null){
passwordView.setError(null);
}
}
});
builder.setView(dialogView);
builder.setMessage("Please enter password to finish with action");
builder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
/* do something when click happen, in this case mostly like dummy because data return later
* after validation or immediately if required*/
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setTitle("Confirm password");
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(final DialogInterface dialogInterface) {
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
if(passwordView == null || !isAdded()){
return;
}
String password = passwordView.getText().toString();
if(PrefUtils.isPasswordValid(getActivity(), password)){
if(resultListener == null){
return;
}
/* Return result and dismiss dialog*/
resultListener.onValidPassword();
dialog.dismiss();
} else {
/* Show an error if entered password is invalid and keep dialog
* shown to the user*/
String error = getActivity().getString(R.string.message_password_not_valid);
passwordView.setError(error);
}
}
});
}
});
return dialog;
}
/**
* Custom callback to return result if entered password is valid
*/
public static interface OnPaswordCheckResult{
void onValidPassword();
}
}