[android] BottomSheetDialogFragment의 상태를 확장 됨으로 설정

Android 지원 디자인 라이브러리 (v23.2.1)를 BottomSheetDialogFragment사용 BottomSheetBehavior#setState(STATE_EXPANDED)하여 확장 으로 확장 되는 조각의 상태를 어떻게 설정 합니까?

https://code.google.com/p/android/issues/detail?id=202396 말한다 :

하단 시트는 처음에 STATE_COLLAPSED로 설정됩니다. 확장하려면 BottomSheetBehavior # setState (STATE_EXPANDED)를 호출합니다. 뷰 레이아웃 전에는 메서드를 호출 할 수 없습니다.

제안 연습 첫번째 팽창 할 뷰를 필요로하지만, 나는 확실히 내가 조각 위에 BottomSheetBehaviour을 설정합니다 방법을 모르겠어요 ( BottomSheetDialogFragment).

View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);



답변

“뷰 레이아웃 전에는 메소드를 호출 할 수 없습니다.”

위의 텍스트가 단서입니다.

대화 상자에는 대화 상자가 표시 되면 시작되는 리스너가 있습니다. 배치되어 있지 않으면 대화 상자를 표시 할 수 없습니다.

따라서 onCreateDialog()모달 하단 시트 ( BottomSheetFragment)에서 대화 상자를 반환하기 직전에 (또는 대화 상자에 대한 참조가 있으면 어디에서나) 다음을 호출하십시오.

// This listener's onShow is fired when the dialog is shown
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
    @Override
    public void onShow(DialogInterface dialog) {

        // In a previous life I used this method to get handles to the positive and negative buttons
        // of a dialog in order to change their Typeface. Good ol' days.

        BottomSheetDialog d = (BottomSheetDialog) dialog;

        // This is gotten directly from the source of BottomSheetDialog
        // in the wrapInBottomSheet() method
        FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet);

        // Right here!
        BottomSheetBehavior.from(bottomSheet)
            .setState(BottomSheetBehavior.STATE_EXPANDED);
    }
});

제 경우에는 제 관습 BottomSheet은 다음과 같습니다.

@SuppressWarnings("ConstantConditions")
public class ShareBottomSheetFragment extends AppCompatDialogFragment {

    @NonNull @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        BottomSheetDialog dialog =
                new BottomSheetDialog(getActivity(), R.style.Haute_Dialog_ShareImage);

        dialog.setContentView(R.layout.dialog_share_image);

        dialog.findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dismiss();
            }
        });

        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog d = (BottomSheetDialog) dialog;

                FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet);
                BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        });

        SwitchCompat switchview = (SwitchCompat) dialog.findViewById(R.id.switchview);
        switchview.setTypeface(FontCache.get(dialog.getContext(), lookup(muli, NORMAL)));

        return dialog;
    }
}

이것이 도움이되는지 알려주세요.

최신 정보

다음 BottomSheetDialogFragment과 같이 재정의 할 수도 있습니다 .

public class SimpleInitiallyExpandedBottomSheetFragment extends BottomSheetDialogFragment {

    @NonNull @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog d = (BottomSheetDialog) dialog;

                FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet);
                BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        });

        // Do something with your dialog like setContentView() or whatever
        return dialog;
    }
}

그러나 나는 기본 BottomSheetFragment이 반환하는 것 외에는 아무것도하지 않기 때문에 왜 누군가가 그렇게하고 싶어하는지 알지 못합니다 BottomSheetDialog.

ANDROIDX 업데이트

AndroidX를 사용하는 경우 이전에에서 찾은 리소스 android.support.design.R.id.design_bottom_sheet는 이제에서 찾을 수 있습니다 com.google.android.material.R.id.design_bottom_sheet.


답변

당신이 사용하려는 경우 efeturi의 대답은, 그러나, 중대하다 onCreateView을 () 로가는 반대로, 당신의 BottomSheet을 만들 이 onCreateDialog () , 여기 당신이 아래에 추가해야합니다 코드입니다 onCreateView () 메소드는 :

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    getDialog().setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
            BottomSheetDialog d = (BottomSheetDialog) dialog;
            View bottomSheetInternal = d.findViewById(android.support.design.R.id.design_bottom_sheet);
            BottomSheetBehavior.from(bottomSheetInternal).setState(BottomSheetBehavior.STATE_EXPANDED);
        }
    });
    return inflater.inflate(R.layout.your_bottomsheet_content_layout, container, false);
}


답변

단순하고 우아한 솔루션 :

BottomSheetDialogFragment 이를 해결하기 위해 하위 분류 될 수 있습니다.

class NonCollapsableBottomSheetDialogFragment extends BottomSheetDialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);

        bottomSheetDialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                FrameLayout bottomSheet = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);

                BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
                behavior.setSkipCollapsed(true);
                behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        });
        return bottomSheetDialog;
    }
}

따라서 BottomSheetDialogFragment자신의 하단 시트를 만드는 대신이 클래스를 확장하십시오 .

노트

프로젝트에서 이전 Android 지원 라이브러리를 사용 com.google.android.material.R.id.design_bottom_sheet하는 android.support.design.R.id.design_bottom_sheet경우로 변경 합니다 .


답변

위의 것이 더 좋다고 생각합니다. 슬프게도 나는 해결하기 전에 그러한 해결책을 찾지 못했습니다. 하지만 내 솔루션을 작성하십시오. 모두 비슷합니다.

================================================ ===============================

나는 같은 문제에 직면 해있다. 이것이 제가 해결 한 것입니다. 동작은 동작을 얻을 수있는 BottomSheetDialog에 숨겨져 있습니다. 부모 레이아웃을 CooridateLayout으로 변경하지 않으려면 이것을 시도 할 수 있습니다.

1 단계 : BottomSheetDialogFragment 사용자 지정

open class CBottomSheetDialogFragment : BottomSheetDialogFragment() {
   //wanna get the bottomSheetDialog
   protected lateinit var dialog : BottomSheetDialog
   override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
      dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
      return dialog
   }

   //set the behavior here
   fun setFullScreen(){
      dialog.behavior.state = STATE_EXPANDED
   }
}

2 단계 : 조각이이 사용자 지정 조각을 확장하도록합니다.

class YourBottomSheetFragment : CBottomSheetDialogFragment(){

   //make sure invoke this method after view is built
   //such as after OnActivityCreated(savedInstanceState: Bundle?)
   override fun onStart() {
      super.onStart()
      setFullScreen()//initiated at onActivityCreated(), onStart()
   }
}


답변

dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog d = (BottomSheetDialog) dialog;

                FrameLayout bottomSheet = (FrameLayout) d.findViewById(android.support.design.R.id.design_bottom_sheet);
                BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        });

null을 반환 BottomSheetBehavior.from(bottomSheet)하기 때문에 NullPointException을 만났습니다 d.findViewById(android.support.design.R.id.design_bottom_sheet).

이상 해요. 이 코드 줄을 DEBUG 모드에서 Android Monitor의 Watches에 추가하고 정상적으로 Framelayout을 반환합니다.

wrapInBottomSheetBottomSheetDialog 의 코드는 다음과 같습니다 .

private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
        final CoordinatorLayout coordinator = (CoordinatorLayout) View.inflate(getContext(),
                R.layout.design_bottom_sheet_dialog, null);
        if (layoutResId != 0 && view == null) {
            view = getLayoutInflater().inflate(layoutResId, coordinator, false);
        }
        FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
        BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback);
        if (params == null) {
            bottomSheet.addView(view);
        } else {
            bottomSheet.addView(view, params);
        }
        // We treat the CoordinatorLayout as outside the dialog though it is technically inside
        if (shouldWindowCloseOnTouchOutside()) {
            coordinator.findViewById(R.id.touch_outside).setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            if (isShowing()) {
                                cancel();
                            }
                        }
                    });
        }
        return coordinator;
    }

때때로, 나는 발견 R.id.design_bottom_sheet동일하지 않습니다 android.support.design.R.id.design_bottom_sheet. 그들은 다른 R.java에서 다른 가치를 가지고 있습니다.

내가 변경 그래서 android.support.design.R.id.design_bottom_sheetR.id.design_bottom_sheet.

dialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog d = (BottomSheetDialog) dialog;

                FrameLayout bottomSheet = (FrameLayout) d.findViewById(R.id.design_bottom_sheet); // use R.java of current project
                BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        });

이제 더 이상 NullPointException이 없습니다.


답변

BottomsheetDialogFragment상태를 적용 onResume하면이 문제가 해결됩니다.

@Override
public void onResume() {
    super.onResume();
    if(mBehavior!=null)
       mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}

onShow(DialogInterface dialog)postDelayed애니메이션 결함이 발생할 수 있습니다


답변

onShow ()를 사용한 모든 결과는 소프트 키보드가 표시 될 때 임의의 렌더링 버그를 유발합니다. 아래 스크린 샷 참조-BottomSheet 대화 상자는 화면 하단에 있지 않지만 키보드가 표시된 것처럼 배치됩니다. 이 문제는 항상 발생하는 것은 아니지만 자주 발생합니다.

여기에 이미지 설명 입력

최신 정보

개인 회원을 반영한 나의 솔루션은 불필요합니다. 소프트 키보드 숨기기 후 대화 상자를 만들고 표시하기 위해 postDelayed (약 100ms)를 사용하는 것이 더 나은 솔루션입니다. 그런 다음 onShow ()를 사용한 위의 솔루션은 괜찮습니다.

Utils.hideSoftKeyboard(this);
mView.postDelayed(new Runnable() {
    @Override
    public void run() {
        MyBottomSheetDialog dialog = new MyBottomSheetDialog();
        dialog.setListener(MyActivity.this);
        dialog.show(getSupportFragmentManager(), TAG_BOTTOM_SHEET_DLG);
    }
}, 100);

그래서 다른 솔루션을 구현하지만 BottomSheetDialog에는 모든 멤버가 개인용으로 있으므로 리플렉션을 사용해야합니다. 그러나 렌더링 버그를 해결합니다. BottomSheetDialogFragment 클래스는 BottomSheetDialog를 생성하는 onCreateDialog 메서드가있는 AppCompatDialogFragment뿐입니다. 내 클래스를 만드는 AppCompatDialogFragment의 자체 자식을 만들어 BottomSheetDialog를 확장하고 개인 동작 멤버에 대한 액세스를 해결하고 onStart 메서드에서 STATE_EXPANDED 상태로 설정합니다.

public class ExpandedBottomSheetDialog extends BottomSheetDialog {

    protected BottomSheetBehavior<FrameLayout> mBehavior;

    public ExpandedBottomSheetDialog(@NonNull Context context, @StyleRes int theme) {
        super(context, theme);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            Field privateField = BottomSheetDialog.class.getDeclaredField("mBehavior");
            privateField.setAccessible(true);
            mBehavior = (BottomSheetBehavior<FrameLayout>) privateField.get(this);
        } catch (NoSuchFieldException e) {
            // do nothing
        } catch (IllegalAccessException e) {
            // do nothing
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (mBehavior != null) {
            mBehavior.setSkipCollapsed(true);
            mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
        }
    }
}


public class AddAttachmentBottomSheetDialog extends AppCompatDialogFragment {

    ....

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new ExpandedBottomSheetDialog(getContext(), getTheme());
    }

    ....
}