ete*_*att 154 android callback android-fragments android-dialogfragment
问题:如何创建从DialogFragment到另一个Fragment的回调.就我而言,涉及的活动应该完全不知道DialogFragment.
考虑一下我
public class MyFragment extends Fragment implements OnClickListener
Run Code Online (Sandbox Code Playgroud)
然后在某些时候我能做到
DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
dialogFrag.show(getFragmentManager, null);
Run Code Online (Sandbox Code Playgroud)
MyDialogFragment的样子
protected OnClickListener listener;
public static DialogFragment newInstance(OnClickListener listener) {
DialogFragment fragment = new DialogFragment();
fragment.listener = listener;
return fragment;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果DialogFragment在其生命周期中暂停和恢复,则无法保证听众会出现.片段中唯一的保证是通过setArguments和getArguments通过Bundle传递的.
如果它应该是监听器,有一种方法可以引用该活动:
public Dialog onCreateDialog(Bundle bundle) {
OnClickListener listener = (OnClickListener) getActivity();
....
return new AlertDialog.Builder(getActivity())
........
.setAdapter(adapter, listener)
.create();
}
Run Code Online (Sandbox Code Playgroud)
但我不希望活动监听事件,我需要一个片段.实际上,它可以是任何实现OnClickListener的Java对象.
考虑通过DialogFragment呈现AlertDialog的Fragment的具体示例.它有Yes/No按钮.如何将这些按钮发送回创建它的Fragment?
Pio*_*rew 186
涉及的活动完全不知道DialogFragment.
片段类:
public class MyFragment extends Fragment {
int mStackLevel = 0;
public static final int DIALOG_FRAGMENT = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mStackLevel = savedInstanceState.getInt("level");
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("level", mStackLevel);
}
void showDialog(int type) {
mStackLevel++;
FragmentTransaction ft = getActivity().getFragmentManager().beginTransaction();
Fragment prev = getActivity().getFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
switch (type) {
case DIALOG_FRAGMENT:
DialogFragment dialogFrag = MyDialogFragment.newInstance(123);
dialogFrag.setTargetFragment(this, DIALOG_FRAGMENT);
dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");
break;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode) {
case DIALOG_FRAGMENT:
if (resultCode == Activity.RESULT_OK) {
// After Ok code.
} else if (resultCode == Activity.RESULT_CANCELED){
// After Cancel code.
}
break;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
DialogFragment类:
public class MyDialogFragment extends DialogFragment {
public static MyDialogFragment newInstance(int num){
MyDialogFragment dialogFragment = new MyDialogFragment();
Bundle bundle = new Bundle();
bundle.putInt("num", num);
dialogFragment.setArguments(bundle);
return dialogFragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.ERROR)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.ok_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, getActivity().getIntent());
}
}
)
.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, getActivity().getIntent());
}
})
.create();
}
}
Run Code Online (Sandbox Code Playgroud)
Ogu*_*can 73
TargetFragment解决方案似乎不是对话框片段的最佳选择,因为它可能会IllegalStateException
在应用程序被销毁并重新创建后创建.在这种情况下FragmentManager
找不到目标片段,你会得到一个这样IllegalStateException
的消息:
"关键android:target_state:index 1"不再存在片段
它似乎Fragment#setTargetFragment()
不是为了孩子和父母片段之间的沟通,而是为了兄弟片段之间的沟通.
所以另一种方法是使用ChildFragmentManager
父片段创建这样的对话框片段,而不是使用以下活动FragmentManager
:
dialogFragment.show(ParentFragment.this.getChildFragmentManager(), "dialog_fragment");
Run Code Online (Sandbox Code Playgroud)
通过使用一个接口,在onCreate
方法中DialogFragment
你可以得到父片段:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
callback = (Callback) getParentFragment();
} catch (ClassCastException e) {
throw new ClassCastException("Calling fragment must implement Callback interface");
}
}
Run Code Online (Sandbox Code Playgroud)
剩下的就是在这些步骤之后调用你的回调方法.
有关该问题的详细信息,请访问以下链接:https: //code.google.com/p/android/issues/detail?id = 54520
Rui*_*Rui 34
也许有点晚了,但可能会帮助其他人像我一样有同样的问题.
您可以在显示之前使用setTargetFragment
on Dialog
,并在对话框中调用getTargetFragment
以获取参考.
Ger*_*eto 33
推荐的方法是使用新的Fragment Result API。
通过使用它,您不需要重写 onAttach(context)或setTargetFragment(),后者现已弃用。
1 - 在父Fragment上添加结果监听器onCreate
:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
childFragmentManager.setFragmentResultListener("requestKey", this) { key, bundle ->
val result = bundle.getString("bundleKey")
}
}
Run Code Online (Sandbox Code Playgroud)
2- 在子Fragment 上,设置结果(例如,在按钮单击侦听器上):
button.setOnClickListener {
val result = "resultSample"
setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}
Run Code Online (Sandbox Code Playgroud)
有关文档的更多信息:https ://developer.android.com/guide/fragments/communicate#fragment-result
希望能帮助到你!
Vij*_*ede 31
我按照这个简单的步骤来做这些事情.
DialogFragmentCallbackInterface
某些方法一样创建界面callBackMethod(Object data)
.你打算传递数据.DialogFragmentCallbackInterface
在你的片段中实现接口了MyFragment implements DialogFragmentCallbackInterface
在DialogFragment
创建时将您的调用片段设置MyFragment
为创建DialogFragment
使用myDialogFragment.setTargetFragment(this, 0)
检查setTargetFragment(Fragment fragment,int requestCode)的目标片段
MyDialogFragment dialogFrag = new MyDialogFragment();
dialogFrag.setTargetFragment(this, 1);
Run Code Online (Sandbox Code Playgroud)DialogFragment
通过调用getTargetFragment()
并将其转换为您的目标片段对象DialogFragmentCallbackInterface
.现在您可以使用此接口将数据发送到您的片段.
DialogFragmentCallbackInterface callback =
(DialogFragmentCallbackInterface) getTargetFragment();
callback.callBackMethod(Object data);
Run Code Online (Sandbox Code Playgroud)
这一切都完成了!只需确保您已在片段中实现此接口.
Edw*_*rey 19
在与其他碎片通信指南说的片段应该通过相关的活动交流.
通常,您会希望一个片段与另一个片段进行通信,例如根据用户事件更改内容.所有Fragment-to-Fragment通信都是通过相关的Activity完成的.两个碎片永远不应该直接通信.
Jam*_*ken 12
您应该interface
在片段类中定义一个并在其父活动中实现该接口.详细信息请参见http://developer.android.com/guide/components/fragments.html#EventCallbacks.代码看起来类似于:
分段:
public static class FragmentA extends DialogFragment {
OnArticleSelectedListener mListener;
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
}
Run Code Online (Sandbox Code Playgroud)
活动:
public class MyActivity extends Activity implements OnArticleSelectedListener{
...
@Override
public void onArticleSelected(Uri articleUri){
}
...
}
Run Code Online (Sandbox Code Playgroud)
根据官方文档:
此片段的可选目标。例如,如果此片段由另一个片段启动,并且在完成后想要将结果返回给第一个片段,则可以使用此方法。此处设置的目标通过 FragmentManager#putFragment 跨实例保留。
返回由 setTargetFragment(Fragment, int) 设置的目标片段。
所以你可以这样做:
// In your fragment
public class MyFragment extends Fragment implements OnClickListener {
private void showDialog() {
DialogFragment dialogFrag = MyDialogFragment.newInstance(this);
// Add this
dialogFrag.setTargetFragment(this, 0);
dialogFrag.show(getFragmentManager, null);
}
...
}
// then
public class MyialogFragment extends DialogFragment {
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Then get it
Fragment fragment = getTargetFragment();
if (fragment instanceof OnClickListener) {
listener = (OnClickListener) fragment;
} else {
throw new RuntimeException("you must implement OnClickListener");
}
}
...
}
Run Code Online (Sandbox Code Playgroud)
为片段设置侦听器的正确方法是在附加片段时对其进行设置。我遇到的问题是从未调用过 onAttachFragment()。经过一番调查,我意识到我一直在使用getFragmentManager而不是getChildFragmentManager
这是我如何做到的:
MyDialogFragment dialogFragment = MyDialogFragment.newInstance("title", "body");
dialogFragment.show(getChildFragmentManager(), "SOME_DIALOG");
Run Code Online (Sandbox Code Playgroud)
将其附加到 onAttachFragment 中:
@Override
public void onAttachFragment(Fragment childFragment) {
super.onAttachFragment(childFragment);
if (childFragment instanceof MyDialogFragment) {
MyDialogFragment dialog = (MyDialogFragment) childFragment;
dialog.setListener(new MyDialogFragment.Listener() {
@Override
public void buttonClicked() {
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
更新:请注意,如果有人感兴趣,我可以分享使用视图模型更简单的方法。
Kotlin 伙计们,我们走了!
所以我们的问题是我们创建了一个活动,MainActivity
在那个活动上我们创建了一个片段,FragmentA
现在我们想在FragmentA
调用它的基础上创建一个对话框片段FragmentB
。我们如何FragmentB
在FragmentA
不经过的情况下从back to得到结果MainActivity
?
笔记:
FragmentA
是 的子片段MainActivity
。要管理在 中创建的片段,FragmentA
我们将使用childFragmentManager
which 来做到这一点!FragmentA
是 的父片段FragmentB
,FragmentA
要从内部访问,FragmentB
我们将使用parenFragment
.话虽如此,在里面FragmentA
,
class FragmentA : Fragment(), UpdateNameListener {
override fun onSave(name: String) {
toast("Running save with $name")
}
// call this function somewhere in a clickListener perhaps
private fun startUpdateNameDialog() {
FragmentB().show(childFragmentManager, "started name dialog")
}
}
Run Code Online (Sandbox Code Playgroud)
这是对话片段FragmentB
。
class FragmentB : DialogFragment() {
private lateinit var listener: UpdateNameListener
override fun onAttach(context: Context) {
super.onAttach(context)
try {
listener = parentFragment as UpdateNameListener
} catch (e: ClassCastException) {
throw ClassCastException("$context must implement UpdateNameListener")
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let {
val builder = AlertDialog.Builder(it)
val binding = UpdateNameDialogFragmentBinding.inflate(LayoutInflater.from(context))
binding.btnSave.setOnClickListener {
val name = binding.name.text.toString()
listener.onSave(name)
dismiss()
}
builder.setView(binding.root)
return builder.create()
} ?: throw IllegalStateException("Activity can not be null")
}
}
Run Code Online (Sandbox Code Playgroud)
这是连接两者的界面。
interface UpdateNameListener {
fun onSave(name: String)
}
Run Code Online (Sandbox Code Playgroud)
就是这样。
归档时间: |
|
查看次数: |
130859 次 |
最近记录: |