Android 대화 상자 조각 대 대화 상자
가 구글을 사용하는 합니다.DialogFragment한 단한것아라 Dialog을 이용하여Fragments API하지만 고립된 것을 사용하는 것은 터무니없는 일입니다.DialogFragment간단한 예-아니오 확인 메시지 상자의 경우.이 경우 가장 좋은 방법은 무엇입니까?
예, 용을 사용합니다.DialogFragment 그고리로.onCreateDialog AlertDialog Builder를 수 .AlertDialogYes/No confirmation(예/아니오 확인) 버튼이 있습니다.코드가 전혀 없습니다.
의 fragment에서 를 처리하는 과 관련하여 다양한 방법이 , 저는 " 의단당서이벤를처트리것는하다다정만방있니의합신, 메는단를지시히순저지겠법이양한련"를 정의합니다.Handler내 안에서Fragment그것을 에 전달합니다.DialogFragment생성자를 통해 메시지를 전달한 다음 다양한 클릭 이벤트에 따라 내 단편의 처리기로 메시지를 다시 전달합니다.다시 말씀드리지만 저는 다음과 같은 방법이 가능합니다.
대화상자에서 메시지를 유지하고 생성자에서 인스턴스화합니다.
private Message okMessage;
...
okMessage = handler.obtainMessage(MY_MSG_WHAT, MY_MSG_OK);
» onClickListener대화 상자에서 해당 처리기를 호출합니다.
public void onClick(.....
if (which == DialogInterface.BUTTON_POSITIVE) {
final Message toSend = Message.obtain(okMessage);
toSend.sendToTarget();
}
}
편집
그리고 또Message 가능합니다. 다니합가능에 할 수 . 저장할 수 있습니다.onSaveInstanceState합니다.
outState.putParcelable("okMessage", okMessage);
그럼인에서.onCreate
if (savedInstanceState != null) {
okMessage = savedInstanceState.getParcelable("okMessage");
}
앱에서 대화 상자를 많이 사용하는 경우 YesNoDialog 및 OkDialog와 같은 일반 DialogFragment 하위 클래스를 만들고 제목과 메시지를 전달할 수 있습니다.
public class YesNoDialog extends DialogFragment
{
public static final String ARG_TITLE = "YesNoDialog.Title";
public static final String ARG_MESSAGE = "YesNoDialog.Message";
public YesNoDialog()
{
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
Bundle args = getArguments();
String title = args.getString(ARG_TITLE);
String message = args.getString(ARG_MESSAGE);
return new AlertDialog.Builder(getActivity())
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, null);
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_CANCELED, null);
}
})
.create();
}
}
그런 다음 다음을 사용하여 호출합니다.
DialogFragment dialog = new YesNoDialog();
Bundle args = new Bundle();
args.putString(YesNoDialog.ARG_TITLE, title);
args.putString(YesNoDialog.ARG_MESSAGE, message);
dialog.setArguments(args);
dialog.setTargetFragment(this, YES_NO_CALL);
dialog.show(getFragmentManager(), "tag");
그 를 그고그결처리다니합를과리로 합니다.onActivityResult.
경고 대화상자에서 DialogFragment 사용:
API 레벨 13이 도입된 이후:
활동의 showDialog 메서드는 더 이상 사용되지 않습니다.코드의 다른 곳에서 대화 상자를 호출하는 것은 사용자가 직접 대화 상자를 관리해야 하므로 권장되지 않습니다(예: 방향 변경).
차이 대화 상자 조각 - 경고 대화 상자
그들은 그렇게 많이 다른가요?DialogFragment 관련 Android 참조:
DialogFragment는 대화창을 표시하는 조각으로, 활동 창 위에 떠 있습니다.이 조각에는 조각의 상태에 따라 적절한 대화 상자 개체가 포함되어 있습니다.대화상자의 제어(표시, 숨김, 해제 시기 결정)는 대화상자에 대한 직접 호출이 아닌 API를 통해 수행되어야 합니다.
기타 참고 사항
- 프래그먼트는 화면 크기가 다른 장치의 다양성으로 인해 Android 프레임워크에서 자연스러운 진화입니다.
- DialogFragments 및 Fragments는 지원 라이브러리에서 사용할 수 있으며 현재 사용되는 모든 Android 버전에서 클래스를 사용할 수 있습니다.
을 사용하는 것이 좋습니다.DialogFragment.
물론, "예/아니오" 대화 상자를 만드는 것은 단순한 작업이어야 하지만 유사한 대화 상자를 만드는 것은 매우 복잡합니다.Dialog놀라울 정도로 복잡합니다.
(활동 수명 주기로 인해 작업이 복잡해짐)Activity대화 상자의 수명 주기를 관리합니다. 사용자 지정 매개 변수(예: 사용자 지정 메시지)를 전달할 방법이 없습니다.Activity.showDialog8 이하의 API 레벨을 사용하는 경우)
좋은 점은 당신이 보통 그 위에 당신만의 추상화를 구축할 수 있다는 것입니다.DialogFragment아주 쉽게
작성기 패턴이 있는 일반 경고 대화상자 조각
프로젝트에서 이미 사용했습니다.AlertDialog.Builder문제가 있다는 걸 알기 전에 이미 많이 알고 있었어요.하지만, 저는 제 앱 어디에서도 그렇게 많은 코드를 변경하고 싶지 않았습니다.게다가, 저는 사실 패스의 팬입니다.OnClickListeners필요한 익명 클래스(즉, 사용 시)setPositiveButton(),setNegativeButton()대화 상자 조각과 홀더 조각 사이의 통신을 위해 수천 개의 콜백 방법을 구현해야 하는 대신, 제 의견으로는 매우 혼란스럽고 복잡한 코드로 이어질 수 있습니다.특히 한 조각에 여러 개의 서로 다른 대화 상자가 있는 경우 콜백 구현에서 현재 표시되는 대화 상자를 구분해야 합니다.
따라서 다양한 접근 방식을 결합하여 일반적인 접근 방식을 만들었습니다.AlertDialogFragment정확히 다음과 같이 사용할 수 있는 도우미 클래스 AlertDialog:
솔루션
(코드에 Java 8 람다 식을 사용하고 있으므로 람다 식을 사용하지 않는 경우 코드의 일부를 변경해야 할 수도 있습니다.
/**
* Helper class for dialog fragments to show a {@link AlertDialog}. It can be used almost exactly
* like a {@link AlertDialog.Builder}
* <p />
* Creation Date: 22.03.16
*
* @author felix, http://flx-apps.com/
*/
public class AlertDialogFragment extends DialogFragment {
protected FragmentActivity activity;
protected Bundle args;
protected String tag = AlertDialogFragment.class.getSimpleName();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = getActivity();
args = getArguments();
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = setDialogDefaults(new AlertDialog.Builder(getActivity())).create();
if (args.containsKey("gravity")) {
dialog.getWindow().getAttributes().gravity = args.getInt("gravity");
}
dialog.setOnShowListener(d -> {
if (dialog != null && dialog.findViewById((android.R.id.message)) != null) {
((TextView) dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
}
});
return dialog;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (args.containsKey("onDismissListener")) {
Parcelable onDismissListener = args.getParcelable("onDismissListener");
if (onDismissListener != null && onDismissListener instanceof ParcelableOnDismissListener) {
((ParcelableOnDismissListener) onDismissListener).onDismiss(this);
}
}
}
/**
* Sets default dialog properties by arguments which were set using {@link #builder(FragmentActivity)}
*/
protected AlertDialog.Builder setDialogDefaults(AlertDialog.Builder builder) {
args = getArguments();
activity = getActivity();
if (args.containsKey("title")) {
builder.setTitle(args.getCharSequence("title"));
}
if (args.containsKey("message")) {
CharSequence message = args.getCharSequence("message");
builder.setMessage(message);
}
if (args.containsKey("viewId")) {
builder.setView(getActivity().getLayoutInflater().inflate(args.getInt("viewId"), null));
}
if (args.containsKey("positiveButtonText")) {
builder.setPositiveButton(args.getCharSequence("positiveButtonText"), (dialog, which) -> {
onButtonClicked("positiveButtonListener", which);
});
}
if (args.containsKey("negativeButtonText")) {
builder.setNegativeButton(args.getCharSequence("negativeButtonText"), (dialog, which) -> {
onButtonClicked("negativeButtonListener", which);
});
}
if (args.containsKey("neutralButtonText")) {
builder.setNeutralButton(args.getCharSequence("neutralButtonText"), (dialog, which) -> {
onButtonClicked("neutralButtonListener", which);
});
}
if (args.containsKey("items")) {
builder.setItems(args.getStringArray("items"), (dialog, which) -> {
onButtonClicked("itemClickListener", which);
});
}
// @formatter:off
// FIXME this a pretty hacky workaround: we don't want to show the dialog if onClickListener of one of the dialog's button click listener were lost
// the problem is, that there is no (known) solution for parceling a OnClickListener in the long term (only for state changes like orientation change,
// but not if the Activity was completely lost)
if (
(args.getParcelable("positiveButtonListener") != null && !(args.getParcelable("positiveButtonListener") instanceof ParcelableOnClickListener)) ||
(args.getParcelable("negativeButtonListener") != null && !(args.getParcelable("negativeButtonListener") instanceof ParcelableOnClickListener)) ||
(args.getParcelable("neutralButtonListener") != null && !(args.getParcelable("neutralButtonListener") instanceof ParcelableOnClickListener)) ||
(args.getParcelable("itemClickListener") != null && !(args.getParcelable("itemClickListener") instanceof ParcelableOnClickListener))
) {
new DebugMessage("Forgot onClickListener. Needs to be dismissed.")
.logLevel(DebugMessage.LogLevel.VERBOSE)
.show();
try {
dismissAllowingStateLoss();
} catch (NullPointerException | IllegalStateException ignored) {}
}
// @formatter:on
return builder;
}
public interface OnDismissListener {
void onDismiss(AlertDialogFragment dialogFragment);
}
public interface OnClickListener {
void onClick(AlertDialogFragment dialogFragment, int which);
}
protected void onButtonClicked(String buttonKey, int which) {
ParcelableOnClickListener parcelableOnClickListener = getArguments().getParcelable(buttonKey);
if (parcelableOnClickListener != null) {
parcelableOnClickListener.onClick(this, which);
}
}
// region Convenience Builder Pattern class almost similar to AlertDialog.Builder
// =============================================================================================
public AlertDialogFragment builder(FragmentActivity activity) {
this.activity = activity;
this.args = new Bundle();
return this;
}
public AlertDialogFragment addArguments(Bundle bundle) {
args.putAll(bundle);
return this;
}
public AlertDialogFragment setTitle(int titleStringId) {
return setTitle(activity.getString(titleStringId));
}
public AlertDialogFragment setTitle(CharSequence title) {
args.putCharSequence("title", title);
return this;
}
public AlertDialogFragment setMessage(int messageStringId) {
return setMessage(activity.getString(messageStringId));
}
public AlertDialogFragment setMessage(CharSequence message) {
args.putCharSequence("message", message);
return this;
}
public AlertDialogFragment setPositiveButton(int textStringId, OnClickListener onClickListener) {
return setPositiveButton(activity.getString(textStringId), onClickListener);
}
public AlertDialogFragment setPositiveButton(CharSequence text, AlertDialogFragment.OnClickListener onClickListener) {
args.putCharSequence("positiveButtonText", text);
args.putParcelable("positiveButtonListener", createParcelableOnClickListener(onClickListener));
return this;
}
public AlertDialogFragment setNegativeButton(int textStringId, AlertDialogFragment.OnClickListener onClickListener) {
return setNegativeButton(activity.getString(textStringId), onClickListener);
}
public AlertDialogFragment setNegativeButton(CharSequence text, AlertDialogFragment.OnClickListener onClickListener) {
args.putCharSequence("negativeButtonText", text);
args.putParcelable("negativeButtonListener", createParcelableOnClickListener(onClickListener));
return this;
}
public AlertDialogFragment setNeutralButton(int textStringId, AlertDialogFragment.OnClickListener onClickListener) {
return setNeutralButton(activity.getString(textStringId), onClickListener);
}
public AlertDialogFragment setNeutralButton(CharSequence text, AlertDialogFragment.OnClickListener onClickListener) {
args.putCharSequence("neutralButtonText", text);
args.putParcelable("neutralButtonListener", createParcelableOnClickListener(onClickListener));
return this;
}
public AlertDialogFragment setOnDismissListener(OnDismissListener onDismissListener) {
if (onDismissListener == null) {
return this;
}
Parcelable p = new ParcelableOnDismissListener() {
@Override
public void onDismiss(AlertDialogFragment dialogFragment) {
onDismissListener.onDismiss(dialogFragment);
}
};
args.putParcelable("onDismissListener", p);
return this;
}
public AlertDialogFragment setItems(String[] items, AlertDialogFragment.OnClickListener onClickListener) {
args.putStringArray("items", items);
args.putParcelable("itemClickListener", createParcelableOnClickListener(onClickListener));
return this;
}
public AlertDialogFragment setView(int viewId) {
args.putInt("viewId", viewId);
return this;
}
public AlertDialogFragment setGravity(int gravity) {
args.putInt("gravity", gravity);
return this;
}
public AlertDialogFragment setTag(String tag) {
this.tag = tag;
return this;
}
public AlertDialogFragment create() {
setArguments(args);
return AlertDialogFragment.this;
}
public AlertDialogFragment show() {
create();
try {
super.show(activity.getSupportFragmentManager(), tag);
}
catch (IllegalStateException e1) {
/**
* this whole part is used in order to attempt to show the dialog if an
* {@link IllegalStateException} was thrown (it's kinda comparable to
* {@link FragmentTransaction#commitAllowingStateLoss()}
* So you can remove all those dirty hacks if you are sure that you are always
* properly showing dialogs in the right moments
*/
new DebugMessage("got IllegalStateException attempting to show dialog. trying to hack around.")
.logLevel(DebugMessage.LogLevel.WARN)
.exception(e1)
.show();
try {
Field mShownByMe = DialogFragment.class.getDeclaredField("mShownByMe");
mShownByMe.setAccessible(true);
mShownByMe.set(this, true);
Field mDismissed = DialogFragment.class.getDeclaredField("mDismissed");
mDismissed.setAccessible(true);
mDismissed.set(this, false);
}
catch (Exception e2) {
new DebugMessage("error while showing dialog")
.exception(e2)
.logLevel(DebugMessage.LogLevel.ERROR)
.show();
}
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
transaction.add(this, tag);
transaction.commitAllowingStateLoss(); // FIXME hacky and unpredictable workaround
}
return AlertDialogFragment.this;
}
@Override
public int show(FragmentTransaction transaction, String tag) {
throw new NoSuchMethodError("Please use AlertDialogFragment.show()!");
}
@Override
public void show(FragmentManager manager, String tag) {
throw new NoSuchMethodError("Please use AlertDialogFragment.show()!");
}
protected ParcelableOnClickListener createParcelableOnClickListener(AlertDialogFragment.OnClickListener onClickListener) {
if (onClickListener == null) {
return null;
}
return new ParcelableOnClickListener() {
@Override
public void onClick(AlertDialogFragment dialogFragment, int which) {
onClickListener.onClick(dialogFragment, which);
}
};
}
/**
* Parcelable OnClickListener (can be remembered on screen rotation)
*/
public abstract static class ParcelableOnClickListener extends ResultReceiver implements AlertDialogFragment.OnClickListener {
public static final Creator<ResultReceiver> CREATOR = ResultReceiver.CREATOR;
ParcelableOnClickListener() {
super(null);
}
@Override
public abstract void onClick(AlertDialogFragment dialogFragment, int which);
}
/**
* Parcelable OnDismissListener (can be remembered on screen rotation)
*/
public abstract static class ParcelableOnDismissListener extends ResultReceiver implements AlertDialogFragment.OnDismissListener {
public static final Creator<ResultReceiver> CREATOR = ResultReceiver.CREATOR;
ParcelableOnDismissListener() {
super(null);
}
@Override
public abstract void onDismiss(AlertDialogFragment dialogFragment);
}
// =============================================================================================
// endregion
}
사용.
// showing a normal alert dialog with state loss on configuration changes (like device rotation)
new AlertDialog.Builder(getActivity())
.setTitle("Are you sure? (1)")
.setMessage("Do you really want to do this?")
.setPositiveButton("Yes", (dialog, which) -> Toast.makeText(getContext(), "Yes clicked", Toast.LENGTH_SHORT).show())
.setNegativeButton("Cancel", null)
.show();
// showing a dialog fragment using the helper class with no state loss on configuration changes
new AlertDialogFragment.builder(getActivity())
.setTitle("Are you sure? (2)")
.setMessage("Do you really want to do this?")
.setPositiveButton("Yes", (dialog, which) -> Toast.makeText(getContext(), "Yes clicked", Toast.LENGTH_SHORT).show())
.setNegativeButton("Cancel", null)
.show();
제 솔루션을 공유하기 위해서뿐만 아니라 여러분의 의견을 듣고 싶어서 이 글을 올립니다.이 접근법은 합법적입니까, 아니면 어느 정도 문제가 있습니까?
@ashishduh의 대답을 약간 단순화할 것을 제안합니다.
public class AlertDialogFragment extends DialogFragment {
public static final String ARG_TITLE = "AlertDialog.Title";
public static final String ARG_MESSAGE = "AlertDialog.Message";
public static void showAlert(String title, String message, Fragment targetFragment) {
DialogFragment dialog = new AlertDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
dialog.setArguments(args);
dialog.setTargetFragment(targetFragment, 0);
dialog.show(targetFragment.getFragmentManager(), "tag");
}
public AlertDialogFragment() {}
@NonNull
@Override
public AlertDialog onCreateDialog(Bundle savedInstanceState)
{
Bundle args = getArguments();
String title = args.getString(ARG_TITLE, "");
String message = args.getString(ARG_MESSAGE, "");
return new AlertDialog.Builder(getActivity())
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, null);
}
})
.create();
}
클래스의 사용자가 구성 요소의 내부를 숙지할 필요가 없으므로 사용이 매우 간단합니다.
AlertDialogFragment.showAlert(title, message, this);
추신. 제 경우에는 간단한 경고 대화상자가 필요했습니다. 그래서 제가 만든 것입니다.예/아니오 또는 필요한 다른 유형에 접근 방식을 적용할 수 있습니다.
DialogFragment는 기본적으로 대화 상자로 사용할 수 있는 Fragment입니다.
다음과 같은 이유로 DialogFragment over Dialog를 사용합니다.
- DialogFragment는 구성 변경 및 저장 및 복원 흐름 후 자동으로 다시 생성됩니다.
- DialogFragment는 Fragment의 전체 라이프사이클을 상속합니다.
- 불법 상태 예외 및 유출된 창 충돌은 더 이상 없습니다.경고 대화 상자가 계속 표시된 상태에서 활동이 삭제되었을 때 이는 매우 일반적이었습니다.
간단한 예 또는 아니오 대화 상자에는 대화 상자를 사용합니다.
생성, 요청 권한, 라이프사이클 오버라이드 등 라이프사이클을 파악해야 하는 보다 복잡한 보기가 필요한 경우 대화상자 조각을 사용합니다.따라서 통화 활동과 통신할 필요 없이 대화 상자가 작동하는 데 필요한 권한과 다른 코드를 구분할 수 있습니다.
대화 상자: 대화 상자는 사용자에게 결정을 내리거나 추가 정보를 입력하라는 메시지를 표시하는 작은 창입니다.
DialogFragment: DialogFragment는 대화 상자를 만들고 호스팅하도록 설계된 특수한 조각 하위 클래스입니다.이를 통해 Fragment Manager는 대화 상자의 상태를 관리하고 구성 변경이 발생할 때 자동으로 대화 상자를 복원할 수 있습니다.
DialogFragment는 대화상자와 Fragment의 기능과 함께 제공됩니다.기본적으로 DialogFragment는 화면 구성 변경 등과 같이 모든 라이프사이클 이벤트를 자동으로 관리합니다.
언급URL : https://stackoverflow.com/questions/7977392/android-dialogfragment-vs-dialog
'source' 카테고리의 다른 글
| Oracle에서 퍼지 텍스트 검색 (0) | 2023.07.31 |
|---|---|
| Swift에서 유형에 대해 표시되는 텍스트 표현을 변경하려면 어떻게 해야 합니까? (0) | 2023.07.31 |
| dotenv 파일이 환경 변수를 로드하지 않습니다. (0) | 2023.07.31 |
| PHP의 텍스트 문자열에서 여러 항목을 대체하는 방법은 무엇입니까? (0) | 2023.07.31 |
| Appdomain 재활용이란 무엇입니까? (0) | 2023.07.31 |