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 .. ฉันไม่คิดว่าเนื้อหาแผ่นด้านล่างมีความเกี่ยวข้องในกรณีนี้ นี่เป็นคำถามที่ทั่วไปมากขึ้นเป็นไปได้หรือไม่ที่จะปิดการใช้งานหนึ่งในแผ่นงานด้านล่าง
Noa Drach

1
สำหรับกรณีการใช้งานของฉันก็ดูเหมือนว่าการตั้งค่าhalfExpandedRatio=0.25fและpeekHeight = 200dpแล้วการรักษาSTATE_COLLAPSEDและSTATE_HALF_EXPANDEDราวกับว่าพวกเขาจะแก้รัฐเดียวกันปัญหา เปิดคำถามไว้ในกรณีที่มีแนวคิดอื่น
Noa Drach

คุณสามารถไปที่ลิงค์นี้มันจะช่วยให้androidhive.info/2017/12/android-working-with-bottom-sheet
UD ..

อย่าลืมตอบคำถามเหล่านี้หากพบว่าตรงตามวัตถุประสงค์ที่ตั้งไว้ในคำถามของคุณ!
CommonsWare

คำตอบ:


3

ค่าของอัตราส่วนที่ขยายครึ่งจะต้องถูกตั้งค่าเป็นค่าระหว่าง 0 และ 1 เอกสิทธิ์ดังนั้นให้ตั้งค่านี้เป็นจำนวนที่ต่ำมากซึ่งแน่นอนว่าจะน้อยกว่าความสูงที่แอบมองของคุณพูดว่า "0.0001f" ด้วยค่านี้คุณไม่ควรเห็นแม้แต่STATE_HALF_EXPANDEDสถานะ รัฐจะมีความผันผวนระหว่างและSTATE_EXPANDEDSTATE_COLLAPSED


ทางเลือกอื่น

วิธีการแก้ปัญหาข้างต้นใช้งานได้และปิดการใช้งานอย่างมีประสิทธิภาพของSTATE_HALF_EXPANDEDรัฐ แต่เป็นการแฮ็ก (IMO) และอาจแตกในอนาคต ตัวอย่างเช่นจะเกิดอะไรขึ้นหากค่าที่เหมาะสมสำหรับอัตราส่วนที่ขยายครึ่งซึ่งอยู่ระหว่างความสูงที่แอบดูและความสูงเต็มจะถูกบังคับใช้ นั่นจะเป็นปัญหา

ข้อกำหนดตามที่ระบุไว้โดย OP คือแผ่นด้านล่างควรเปลี่ยนระหว่างความสูงแอบมองและความสูงเต็ม ไม่มีปัญหากับความสูงแอบมอง แต่ OP ระบุisFitToContents = falseเพื่อให้ได้ความสูงเต็ม (ฉันสมมติว่าแผ่นด้านล่างของเขาอาจจะสั้นกว่าพื้นที่ว่าง)

น่าเสียดายที่เมื่อisFitToContents == falseมีการแนะนำพฤติกรรม "ครึ่งความสูง" เพิ่มเติมว่า OP ต้องการหลีกเลี่ยงและดังนั้นจึงเป็นคำถาม

นอกจากพฤติกรรม "half-height" แล้วยังมีการแนะนำพฤติกรรมอื่นซึ่งก็คือ "offset offset" ออฟเซ็ตที่ขยายจะระบุระยะที่แผ่นด้านล่างสุดเต็มจอจะหยุดลง 100fยกตัวอย่างเช่นค่าของจะออกจาก100pxชายแดนที่ด้านบนของแผ่นด้านล่างเมื่อขยายเต็ม ค่าเริ่มต้นสำหรับออฟเซ็ตที่ขยายเพิ่มเป็นศูนย์

ฉันไม่ได้ตระหนักถึงพฤติกรรมใด ๆ ที่isFitToContents == falseแนะนำนอกเหนือจากที่กล่าวไว้ข้างต้น

ดังนั้นตามข้อกำหนดเหล่านี้เราสามารถทำแผ่นด้านล่างที่เคลื่อนไหวระหว่างความสูงที่มองและความสูงเต็มในขณะที่การระบุisFitToContents == trueจึงหลีกเลี่ยงปัญหา "ความสูงครึ่ง" ไม่มีข้อกำหนดสำหรับออฟเซ็ตที่ไม่ขยายศูนย์ดังนั้นเราจึงไม่ต้องกังวลกับสิ่งนั้น

นี่คือแอพสาธิตสั้น ๆ ที่แสดงให้เห็นว่าเราสามารถตอบสนองความต้องการเหล่านี้ได้ด้วยโครงสร้างแผ่นด้านล่างขวา:

ป้อนคำอธิบายรูปภาพที่นี่

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ทำงาน
Noa Drach

@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_EXPANDEDไปSTATE_COLLAPSEDรู้สึก clunky การเปลี่ยนระหว่างสถานะเป็นภาพเคลื่อนไหวดังนั้นคุณจะเห็นแผ่นด้านล่างหยุดที่STATE_HALF_EXPANDEDและจากนั้นจะย้ายไปที่STATE_COLLAPSED
Noa Drach

คุณสามารถรวมสิ่งนี้กับค่าครึ่งขยายได้เท่ากับ 0 หรือไม่
Ridcully

@Ridcully - 2 ประเด็นที่นี่ - 1. ครึ่งขยายเรดิโอต้องอยู่เหนือ 0 0 2. การตั้งค่าเป็นค่าที่ต่ำมากจะทำให้มันลดลงเหลือน้อยที่สุดเกือบสมบูรณ์ ฉันคิดว่าการรวมคำแนะนำนี้กับวิธีการทำงานของฉันของhalfExpandedState=0.25fb / c แล้วการเปลี่ยนแปลงระหว่างรัฐจะไม่ชัดเจน แต่ผมไม่แน่ใจว่าจะมีการเปลี่ยนแปลงขนาดใหญ่เมื่อเทียบกับสิ่งที่ฉันมีอยู่แล้ว
อะ Drach

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)

หวังว่านี่จะช่วยได้


1

BottomSheetBehavior.setHalfExpandedRatio(0f)การตั้งค่าลอง ไม่มีอะไรมากที่จะส่งผลกระทบต่อSTATE_HALF_EXPANDEDเว้นแต่จะตั้งค่าสถานะด้วย. setState ()อย่างชัดเจน มันก็ควรจะเป็นไปได้ในการสร้างที่กำหนดเองBehaviorซึ่งทอดตัวและไม่ได้มีCoordinatorLayout.Behavior<View> STATE_HALF_EXPANDEDเช่น. ที่ขัดขวางการทุกอย่างด้วย CoordinatorLayout พฤติกรรม


0

ฉันลองวิธีที่แตกต่างกัน แต่ไม่มีเทคนิคใดที่สมบูรณ์แบบ ฉันพยายามดักจับเหตุการณ์ในBottomSheetBehavior.BottomSheetCallback {}และถูกเรียกdismiss()โดยใช้ตรรกะที่กำหนดเอง แต่มันทำให้เกิดการกระตุก

ดังนั้นในที่สุดฉันBottomSheetDialogFragmentก็เพิ่มbottomSheetBehavior.isDraggable = falseสิ่งนี้ทำให้การลากแผ่นด้านล่างโดยการสัมผัสและฉันจัดการการเลิกจ้างโต้ตอบด้วยตัวเอง ในกล่องโต้ตอบพื้นที่ว่างต่อไปได้รับการไล่ออก

โปรดทราบว่าแผ่นด้านล่างยังคงขยายด้วยภาพเคลื่อนไหว เยี่ยมมาก!

ลบล้างความสนุกบน

    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.