Android-바텀 시트의 STATE_HALF_EXPANDED 상태를 비활성화하는 방법


14

나는 2 주 사이에 가야 바닥 시트를, STATE_COLLAPSED그리고 STATE_EXPANDED 이 접힌 때 높이가되어야합니다 200dp및 확장 할 때 전체 화면 일 것이다.

제가 설정을 해요 그래서 BottomSheetBehavior함께

isFitToContents = false
peekHeight = 200dp

halfExpandedRatio그렇지 않으면 STATE_HALF_EXPANDED맨 아래 시트가 화면의 절반을 차지할 때 값을 설정해야합니다 .

나는 일하고 있어요 com.google.android.material:material:1.1.0-rc01

STATE_HALF_EXPANDED상태 를 비활성화하는 방법이 있습니까?

아니면 실제로 설정해야 skipCollapsed=true와 비율 무엇 200dp 수단과 업무의 관점에서 파악, STATE_HALF_EXPANDED그리고 STATE_EXPANDED대신 STATE_COLLAPSED하고STATE_EXPANDED


하단 시트의 모양과 같은 자세한 내용을 알려주십시오.
UD ..

@UD ..이 경우 하단 시트 내용이 관련이 있다고 생각하지 않습니다. 이것은보다 일반적인 질문이 바닥 시트 상태의 해제 하나에 수 있습니다
노아 DRACH

1
내 유스 케이스의 경우, 해당 설정 보인다 것 halfExpandedRatio=0.25fpeekHeight = 200dp다음 치료를 STATE_COLLAPSED하고 STATE_HALF_EXPANDED있는 것처럼 그들은 같은 상태로 해결할 수있는 문제는 문제입니다. 다른 아이디어가있는 경우 질문을 열어 두십시오.
Noa Drach


질문에 제시된 목표를 달성 한 경우 다음 답변 중 하나를 수락하십시오!
CommonsWare

답변:


3

반 확장 비율의 값은 0과 1 독점 사이의 값으로 설정해야합니다 . 따라서이 값을 뾰족한 높이보다 작은 매우 낮은 숫자로 설정하십시오 (예 : "0.0001f"). 이 값을 사용하면 STATE_HALF_EXPANDED상태를 볼 수도 없습니다 . 주 STATE_EXPANDED와 사이에 변동이 STATE_COLLAPSED있습니다.


대체 솔루션

위의 솔루션은 작동하고 효과적으로 STATE_HALF_EXPANDED상태를 비활성화 하지만 해킹 (IMO)이며 향후 중단 될 수 있습니다. 예를 들어, 반 높이 비율과 전체 높이 사이에있는 절반 확장 비율에 대한 합리적인 값이 적용된다면 어떨까요? 문제가 될 것입니다.

OP에 명시된 바와 같이 요구 사항은 바닥 시트가 픽 높이와 전체 높이 사이에서 전환되어야한다는 것입니다. 엿보기 높이에는 문제가 없지만 OP isFitToContents = false는 전체 높이에 도달하도록 지정 합니다. (나는 그의 바닥 시트가 사용 가능한 공간보다 짧을 수 있다고 가정합니다.)

불행하게도 isFitToContents == falseOP가 회피하고 싶어하는 추가 "반 높이"동작이 도입되면 질문이 생깁니다.

"반 높이"동작 외에도 "확장 오프셋"인 다른 동작이 도입되었습니다. 확장 오프셋은 바텀 시트가 전체 화면에서 얼마나 멀리 내려갈지를 지정합니다. 100f예를 들어 값이 100px완전히 확장되면 바텀 시트 상단에 테두리 가 남습니다 . 확장 된 오프셋의 기본값은 0입니다.

isFitToContents == false위에서 언급 한 것 이외의 동작을 인식하지 못했습니다 .

따라서 이러한 요구 사항을 감안할 isFitToContents == true때 "반 높이"문제를 피 하면서 특정 높이와 전체 높이 사이를 이동하는 바닥 시트를 만들 수 있습니까? 0이 아닌 확장 오프셋에 대한 요구 사항이 없으므로 걱정할 필요가 없습니다.

오른쪽 하단 시트 구조로 이러한 요구 사항을 충족 할 수 있음을 보여주는 간단한 데모 앱이 있습니다.

여기에 이미지 설명을 입력하십시오

MainActivity5.kt

class MainActivity5 : BaseActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_main5)  

        val bottomSheet = findViewById<LinearLayout>(R.id.bottom_sheet)  
        val sheetBehavior: BottomSheetBehavior<LinearLayout> = BottomSheetBehavior.from(bottomSheet)  
        sheetBehavior.isFitToContents = true // the default  
  sheetBehavior.peekHeight = 200  

  // Log the states the bottom sheet passes through.  
  sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {  
            override fun onStateChanged(bottomSheet: View, newState: Int) {  
                Log.d("MainActivity", "<<<< $newState = ${translateSheetState(newState)}")  
            }  

            override fun onSlide(bottomSheet: View, slideOffset: Float) {}  
        })  
    }  
}

BaseActivity.kt

open class BaseActivity : AppCompatActivity() {  

    protected fun translateSheetState(state: Int): String {  
        return when (state) {  
            BottomSheetBehavior.STATE_COLLAPSED -> "STATE_COLLAPSED"  
  BottomSheetBehavior.STATE_DRAGGING -> "STATE_DRAGGING"  
  BottomSheetBehavior.STATE_EXPANDED -> "STATE_EXPANDED"  
  BottomSheetBehavior.STATE_HALF_EXPANDED -> "STATE_HALF_EXPANDED"  
  BottomSheetBehavior.STATE_HIDDEN -> "STATE_HIDDEN"  
  BottomSheetBehavior.STATE_SETTLING -> "STATE_SETTLING"  
  else -> "Unknown state: $state"  
  }  
    }  
}

activity_main5.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_orange_light"
        android:orientation="vertical"
        android:scrollbars="none"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="@string/short_text"
            android:textSize="16sp" />

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

하단 시트가 길면 다음과 같은 구조로 스크롤됩니다.

activity_main6.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_orange_light"
        android:orientation="vertical"
        android:scrollbars="none"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="16dp"
                android:text="@string/long_text"
                android:textSize="16sp" />
        </androidx.core.widget.NestedScrollView>
    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

초기 응답과 관련하여-반 확장 비율을 설정하더라도 하단 시트의 매우 얇은 힌트가 여전히 보입니다. 어쨌든, 이것은 내가 찾고있는 행동이 아닙니다. "대체 솔루션"에서 언급 한대로- "하단 시트는 픽 높이와 전체 높이 사이를 전환해야합니다"
Noa Drach

귀하의 "대체 솔루션"이 작동하는 것 같습니다. 제가 필요한 솔루션입니다. 초기 테스트에서 사용해야합니다 isFitToContents = false. 그러나 테스트는 isFitToContents = true
정상적으로

@NoaDrach 하단 시트를 숨길 수있는 경우 하단 시트 오프셋이 계산되는 방식으로 인해 하단에 최소 1px가 표시됩니다. 시트가 숨겨 질 것이라고 생각하지는 않았지만 1px가 표시 sheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN되면 절반 확장 상태에 도달 하면 시트가 숨겨 질 수 있었지만 조금 복잡해졌습니다. 대체 솔루션이 더 좋습니다.
Cheticamp

2

여기에 이미지 설명을 입력하십시오

이미지와 같이 위를 시도하려면 아래 코드를 따르면 도움이 될 것입니다 !!!

public class CollectionsBottomSheet extends BottomSheetDialogFragment {
    private BottomSheetBehavior mBehavior;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
        View view = View.inflate(getContext(), R.layout.collections_layout, null);
        LinearLayout linearLayout = view.findViewById(R.id.root);
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();
        params.height = getScreenHeight();
        linearLayout.setLayoutParams(params);
        dialog.setContentView(view);
        mBehavior = BottomSheetBehavior.from((View) view.getParent());
        return dialog;

    }

    @Override
    public void onStart() {
        super.onStart();
        mBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }

    public static int getScreenHeight() {
        return Resources.getSystem().getDisplayMetrics().heightPixels;
    }
}



xml 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:fitsSystemWindows="true">


    <LinearLayout
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/filter_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:drawableStart="@drawable/ic_cancel"
                android:drawableLeft="@drawable/ic_cancel"
                android:drawablePadding="30dp"
                android:gravity="center_vertical"
                android:padding="12dp"
                android:text="Filters"
                android:textColor="@color/black"
                android:textSize="18sp" />

            <View
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="1" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="10dp"
                android:layout_marginRight="10dp"
                android:padding="5dp"
                android:text="Reset ALL"
                android:textColor="#6f6f6f"
                android:textSize="12sp" />

        </LinearLayout>

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#d8dbdb" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_star"
            android:drawableLeft="@drawable/ic_star"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="GUEST RATINGS"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_money"
            android:drawableLeft="@drawable/ic_money"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="PRICE RANGE"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_loan"
            android:drawableLeft="@drawable/ic_star"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="PAY AT HOTEL"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_folder"
            android:drawableLeft="@drawable/ic_folder"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="COLLECTIONS"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_perm_identity_black_24dp"
            android:drawableLeft="@drawable/ic_perm_identity_black_24dp"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="FACILITIES"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_apartment"
            android:drawableLeft="@drawable/ic_apartment"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="CATEGORIES"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/sort_background"
            android:drawableStart="@drawable/ic_hotel_building"
            android:drawableLeft="@drawable/ic_hotel_building"
            android:drawablePadding="15dp"
            android:padding="15dp"
            android:text="ACCOMMODATION TYPE"
            android:textColor="#6f6f6f"
            android:textSize="16sp" />

    </LinearLayout>


</LinearLayout>

매우 좋은 답변 ... 내 하루를 구했다
unownsp

1

설정 a하려고 addBottomSheetCallback당신에 BottomSheetBehavior, 그리고 당신이 감지 될 때 STATE_HALF_EXPANDED상태를 호출 setState(STATE_HIDDEN)바닥 시트 시도가 중간 상태에 도달 할 때마다 그냥 가까운거야, 그래서.


좋은 생각입니다. 제 경우에는 상태를로 설정 STATE_COLLAPSED하지 않을 것 STATE_HIDDEN입니다. 그러나 나는 그와의 전환 구현하기 위해 노력 STATE_HALF_EXPANDEDSTATE_COLLAPSEDFeel로의 투박한을. 상태 사이의 전환은 사용자가 멈추는 바닥 시트를 볼 수 있도록, 애니메이션 STATE_HALF_EXPANDED및 그것은으로 이동STATE_COLLAPSED
노아 DRACH

이 값을 halfExpandedRatio 0으로 결합 할 수 있습니까?
Ridcully

@Ridcully-2 가지 문제-1. halfExpandedRatio가 0보다 커야합니다. 2.이 값을 매우 낮은 값으로 설정하면 축소 된 상태로 스냅되기 전에 거의 완전히 최소화 (반쪽 확장 상태)됩니다. 이 제안 사항을 작업 솔루션 인 halfExpandedState=0.25fb / c 와 결합하는 것으로 생각 하면 상태 간 전환이 분명하지 않습니다. 그러나, 내가 이미 가지고있는 것에 비해 큰 변화가 될지 확신하지 못합니다
Noa Drach

1

레이아웃이 높이의 3 분의 1이어야하는 비슷한 유스 케이스가있었습니다. 나는 다음을 시도했고 훌륭하게 작동했다.

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bottom_sheet_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/grey"
    android:clickable="true">

    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/rounded_bottom_sheet_background"
        android:orientation="vertical"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

하단 시트에 다음을 설정하여 동적으로 변경해야했지만 XML 에서도이 작업을 수행 할 수 있습니다.

bottomSheet.setPeekHeight(200);// 200px
bottomSheet.setHideable(false);

해제하기 위해 다음 함수를 사용하여 조각에 애니메이션을 추가했습니다.

fragmentTransaction.setCustomAnimations(
                    R.anim.fade_in,
                    R.anim.fade_out,
                    R.anim.fade_in,
                    R.anim.fade_out)

도움이 되었기를 바랍니다



0

다른 방법으로 시도했지만 완벽하게 작동하는 기술은 없습니다. 이벤트를 가로 채려고 시도 하고 사용자 지정 논리를 기반으로 BottomSheetBehavior.BottomSheetCallback {}호출 dismiss()했지만 문제가 발생했습니다.

그래서 마침내, BottomSheetDialogFragment나는 추가 bottomSheetBehavior.isDraggable = false했고 이것은 터치로 바닥 시트를 끌었습니다. 그리고 나는 대화의 해제를 스스로 처리했습니다. 빈 영역 대화 상자에서 어쨌든 해제됩니다.

하단 시트는 여전히 애니메이션과 함께 확장됩니다. 정말 좋습니다!

재미 재정의 onCreateDialog (savedInstanceState : Bundle?) : 대화 상자 {val dialog = super.onCreateDialog (savedInstanceState)

    dialog.setOnShowListener {
        val bottomSheetDialog = it as BottomSheetDialog
        val bottomSheet =
            bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
                ?: return@setOnShowListener

        //Making background to transparent to avoid white background to given space margin.
        bottomSheet.setBackgroundColor(ContextCompat.getColor(context!!, R.color.transparent))

        val inflatedView = fragmentProfileDialogBinding.root
        val parent = inflatedView.parent as View

        val bottomSheetBehavior = BottomSheetBehavior.from(parent)
        bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
        bottomSheetBehavior.isDraggable = false
    }

    return dialog
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.