Android 대화 상자 조각 대 대화 상자
가 구글을 사용하는 합니다.DialogFragment
한 단한것아라 Dialog
을 이용하여Fragments API
하지만 고립된 것을 사용하는 것은 터무니없는 일입니다.DialogFragment
간단한 예-아니오 확인 메시지 상자의 경우.이 경우 가장 좋은 방법은 무엇입니까?
예, 용을 사용합니다.DialogFragment
그고리로.onCreateDialog
AlertDialog Builder를 수 .AlertDialog
Yes/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.showDialog
8 이하의 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 |