programing

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

nasanasas 2020. 11. 29. 11:47
반응형

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이를 처리하기 위해 의 하위 클래스를 작성했습니다 .

public 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경우로 변경 합니다 .


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

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

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


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이 없습니다.


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

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

나는 같은 문제에 직면 해있다. 이것이 내가 해결 한 것입니다. 동작은 동작을 얻을 수있는 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()
   }
}

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());
    }

    ....
}

내가 구현 한 가장 쉬운 방법은 다음과 같습니다. 여기에서 android.support.design.R.id.design_bottom_sheet를 찾고 하단 시트 상태를 EXPANDED 로 설정합니다 .

Without this, my bottom sheet was always stuck in the COLLAPSED state if view height is more than 0.5 of screen height and I have to manually scroll to view full bottom sheet.

class BottomSheetDialogExpanded(context: Context) : BottomSheetDialog(context) {

    private lateinit var mBehavior: BottomSheetBehavior<FrameLayout>

    override fun setContentView(view: View) {
        super.setContentView(view)
        val bottomSheet = window.decorView.findViewById<View>(android.support.design.R.id.design_bottom_sheet) as FrameLayout
        mBehavior = BottomSheetBehavior.from(bottomSheet)
        mBehavior.state = BottomSheetBehavior.STATE_EXPANDED
    }

    override fun onStart() {
        super.onStart()
        mBehavior.state = BottomSheetBehavior.STATE_EXPANDED
    }
}

Similar to uregentx answer, in kotlin, you can declare your fragment class that extends from BottomSheetDialogFragment, and when the view is created you can set the dialog listener default state after the dialog is displayed.

STATE_COLLAPSED: The bottom sheet is visible but only showing its peek height.

STATE_EXPANDED: The bottom sheet is visible and its maximum height.

STATE_HALF_EXPANDED: The bottom sheet is visible but only showing its half height.

    class FragmentCreateGroup : BottomSheetDialogFragment() {
          ...

        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
            // Set dialog initial state when shown
            dialog?.setOnShowListener {
                val bottomSheetDialog = it as BottomSheetDialog
                val sheetInternal: View = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet)!!
                BottomSheetBehavior.from(sheetInternal).state = BottomSheetBehavior.STATE_COLLAPSED
            }

            val view = inflater.inflate(R.layout.fragment_create_group, container, false)
            ...

            return view
        }
    }

Remember using material design implementation in gradle.

implementation "com.google.android.material:material:$version"

Also take a look to material design reference Bottom Sheets

참고 URL : https://stackoverflow.com/questions/35937453/set-state-of-bottomsheetdialogfragment-to-expanded

반응형