英文:
Android's AlertDialog in fragment
问题
我有一个使用选项卡活动(Tabbed Activity)的应用程序,有3个选项卡,每个选项卡都有一个单独的片段(fragment)和布局(layout)。选项卡3具有一些用户配置设置,例如用户名。用户名显示在一个卡片视图(cardview)内,因此我将该卡片视图设置为可点击,点击时会打开一个带有编辑文本的警告对话框(AlertDialog),用于输入用户名。为了构建此对话框,我找到了2种方法。
第一种方法:(此方法在点击卡片视图时运行(On clicklistener)),它非常有效,我没有任何问题,但感觉不像最佳实践。
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setTitle("Enter your Username");
LayoutInflater inflater = getActivity().getLayoutInflater();
View view1 = inflater.inflate(R.layout.editname_layout, null);
alert.setView(view1);
final EditText input = view1.findViewById(R.id.editname);
alert.setPositiveButton("Save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
textView.setText(input.getText().toString());
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Canceled.
}
});
alert.show();
**第二种方法:**我构建了一个单独的DialogFragment,并使用接口将数据发送回片段。这种方法似乎是最佳实践,但我遇到了许多问题,例如...当数据发送回片段时,我无法在接收到数据时使用方法"textView.setText",因为我在onCreateView方法之外接收它,因此textView始终返回null。
public class Dialog extends AppCompatDialogFragment {
private Context context;
public DialogListener listener;
public Dialog(Context context) {
this.context = context;
}
@NonNull
@Override
public android.app.Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.name_layout, null);
final EditText name = (EditText) view.findViewById(R.id.editname);
builder.setView(view)
.setTitle("Username")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setPositiveButton("Save", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
String text = name.getText().toString();
listener.data(text);
Toast.makeText(getActivity(), "Saved", Toast.LENGTH_SHORT).show();
}
});
return builder.create();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
Fragment fragment = new Tab3();
listener = (DialogListener) fragment;
}
catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement DialogListener");
}
}
public interface DialogListener {
void data(String name);
}
}
因此,我正在考虑使用第一种方法,因为它更简单,更容易从中提取文本,但仍然不确定是否是一个好的做法。
提前感谢您!
英文:
I have an app that uses tabbed activity, with 3 tabs, each with a separate fragment and layout. Tab3 has some user-profile settings, like a name for example. Name is displayed inside a cardview, so I made that cardview clickable, and onClick it would open an alertDialog with an edit text to enter the name. to build this dialog I found 2 methods.
First:- (this is run once the cardview is clicked(On clicklistener)) and its working very well and I have no issues with it but it just doesn't feel like a best-practice
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setTitle("Enter your Username");
LayoutInflater inflater = getActivity().getLayoutInflater();
View view1 = inflater.inflate(R.layout.editname_layout, null);
alert.setView(view1);
final EditText input = view1.findViewById(R.id.editname);
alert.setPositiveButton("Save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
textView.setText(input.getText().toString());
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Canceled.
}
});
alert.show();
Second:- is that I build a separate DialogFragment with an interface to send data back to fragment this one feels like a best practice but i have faced many issues with it, such as.. when data is sent back to my fragment, I can't use the method "textView.setText" on the received data as I receive it outside the onCreateView method and thus textView always returns null.
public class Dialog extends AppCompatDialogFragment {
private Context context;
public DialogListener listener;
public Dialog(Context context) {
this.context = context;
}
@NonNull
@Override
public android.app.Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.name_layout, null);
final EditText name = (EditText) view.findViewById(R.id.editname);
builder.setView(view)
.setTitle("Username")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setPositiveButton("Save", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
String text = name.getText().toString();
listener.data(text);
Toast.makeText(getActivity(), "Saved", Toast.LENGTH_SHORT).show();
}
});
return builder.create();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
Fragment fragment = new Tab3();
listener = (DialogListener) fragment;
}
catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement d.l");
}
}
public interface DialogListener {
void data(String name);
}
}
So what I'm thinking is that I should go with the first method as it's easier, and it's easier to extract text from it but still not sure if it would be a good practice.
thanks in advance!
答案1
得分: 1
这不是最佳实践的问题,而是关乎如何设计你的应用程序。
- 第一种解决方案:你可以直接与你的用户界面进行交互。例如:在
textView
中设置新值。但是,如果你编写了许多对话框,请考虑将逻辑进行泛化(第二种解决方案)。 - 第二种解决方案:如果你只想要一个通用的“对话框”,你需要用于它的使用案例,即对话框的多次调用。别忘了:如果你实例化了对话框类,你需要将
textView
传递给它,这样你才能在用户界面中进行更改。
英文:
It's not a question of best practice, it's just how you want to design your App.
- The first solution: You can directly interact with your UI. e.g: Set the new value in
textView
. But if you write a lot of dialogs, think about to generify the logic (the second solution). - The second solution: If you want just a generic
Dialog
, you need the use-case for it = multiple calls for dialogs and don't forget: if you instantiate the Dialog class you need to give him thetextView
if you want to change it in the UI
答案2
得分: 1
优先选择第二种解决方案:
- 您可以拥有自己的自定义 UI 元素。
- 您可以访问生命周期变化(
onResume
,onCreate
等等)。 - 即使在更改方向时也会保持显示(第一种解决方案不会)。
要将数据发送回上一个片段,您可以创建一个片段listener
。
interface MyFragmentListener {
fun onSendBackData(data: Any)
}
class MyFragment : Fragment {
private var listener: MyFragmentListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
listener = when {
context is MyFragmentListener -> context
parentFragment is MyFragmentListener -> parentFragment as MyFragmentListener
else -> error("You should implement MyFragmentListener")
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener {
listener?.onSendBackData("Data")
}
}
}
class Activity : Activity(), MyFragmentListener {
override fun onSendBackData(data: Any) {
textView.text = data.toString()
}
}
英文:
Prefer second solution:
- You can have your custom UI elements.
- You have access to lifecycle changes (
onResume
,onCreate
,etc.). - It keeps showing even when orientation is changed (the first solution doesn't).
And for sending data to previous fragment you can create listener
to fragment.
interface MyFragmentListener {
fun onSendBackData(data: Any)
}
class MyFragment:Fragment {
private var listener: MyFragmentListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
listener = when {
context is MyFragmentListener -> context
parentFragment is MyFragmentListener -> parentFragment as MyFragmentListener
else -> error("You should implement MyFragmentListener")
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener {
listener?.onSendBackData("Data")
}
}
}
class Activity : Activity(), MyFragmentListener {
override fun onSendBackData(data:Any) {
textView.text = data.toString()
}
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论