Menonaktifkan Pengguna menyeret di BottomSheet


100

Saya mencoba untuk menonaktifkan pengguna yang menyeret BottomSheet. Alasan saya ingin menonaktifkan adalah dua hal. 1. Ini mencegah ListViewdari pengguliran ke bawah, 2. Saya tidak ingin pengguna mengabaikan menggunakan menyeret tetapi dengan tombol di BottomSheetView. Inilah yang telah saya lakukan

 bottomSheetBehavior = BottomSheetBehavior.from(bottomAnc);
    bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                //Log.e("BottomSheet", "Expanded");
            } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
                //Log.e("BottomSheet", "Collapsed");
            }
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            // React to dragging events
            bottomSheet.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    int action = MotionEventCompat.getActionMasked(event);
                    switch (action) {
                        case MotionEvent.ACTION_DOWN:
                            return false;
                        default:
                            return true;
                    }
                }
            });
        }
    });

The bottomSheetLayout

    <?xml version="1.0" encoding="utf-8"?><FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="@string/bottom_sheet_behavior"
android:id="@+id/bottomSheet">

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:elevation="10dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

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

            <TextView
                android:id="@+id/text1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="Order Items"
                android:layout_margin="16dp"
                android:textAppearance="@android:style/TextAppearance.Large"/>


            <Button
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:layout_marginRight="5dp"
                android:background="@drawable/bg_accept"/>

            <Button
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:layout_marginRight="8dp"
                android:background="@drawable/bg_cancel"/>

        </LinearLayout>

        <ListView
            android:id="@+id/item_edit"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            android:divider="@color/md_divider_black"
            android:dividerHeight="1dp"/>

    </LinearLayout>

</android.support.v7.widget.CardView>


Tolong, periksa jawaban saya. Saya perhatikan bahwa ini lebih relevan daripada jawaban yang diterima
Vitalii Obideiko

Jawaban:


92

Sekarang mungkin sudah tidak relevan lagi, tetapi saya akan meninggalkannya di sini:

import android.content.Context
import android.util.AttributeSet
import androidx.coordinatorlayout.widget.CoordinatorLayout
import android.view.MotionEvent
import android.view.View
import com.google.android.material.bottomsheet.BottomSheetBehavior

@Suppress("unused")
class LockableBottomSheetBehavior<V : View> : BottomSheetBehavior<V> {
    constructor() : super()
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    var swipeEnabled = true

    override fun onInterceptTouchEvent(
        parent: CoordinatorLayout,
        child: V,
        event: MotionEvent
    ): Boolean {
        return if (swipeEnabled) {
            super.onInterceptTouchEvent(parent, child, event)
        } else {
            false
        }
    }

    override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        return if (swipeEnabled) {
            super.onTouchEvent(parent, child, event)
        } else {
            false
        }
    }

    override fun onStartNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        directTargetChild: View,
        target: View,
        axes: Int,
        type: Int
    ): Boolean {
        return if (swipeEnabled) {
            super.onStartNestedScroll(
                coordinatorLayout,
                child,
                directTargetChild,
                target,
                axes,
                type
            )
        } else {
            false
        }
    }

    override fun onNestedPreScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        dx: Int,
        dy: Int,
        consumed: IntArray,
        type: Int
    ) {
        if (swipeEnabled) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
        }
    }

    override fun onStopNestedScroll(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        type: Int
    ) {
        if (swipeEnabled) {
            super.onStopNestedScroll(coordinatorLayout, child, target, type)
        }
    }

    override fun onNestedPreFling(
        coordinatorLayout: CoordinatorLayout,
        child: V,
        target: View,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        return if (swipeEnabled) {
            super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY)
        } else {
            false
        }
    }
}

Dan gunakan di file xml Anda:

app:layout_behavior="com.your.package.LockableBottomSheetBehavior"

Ini menonaktifkan semua tindakan pengguna, ini dapat digunakan ketika Anda ingin mengontrol BottomSheet hanya secara terprogram.


2
Ini adalah jawaban terbaik, untuk menonaktifkan BottomSheetBehaviour. Seorang pria di atas juga memposting solusi serupa, tetapi dia tidak menulis untuk menimpa acara lain seperti onTouchEvent () . Di sisi lain Anda dapat meningkatkan jawaban Anda jika Anda menempatkan bendera bukan palsu
murt

3
Bagaimana Anda menggunakan ini dengan BottomSheetFragment?
pengguna3144836

7
Anda perlu secara khusus merujuk ke kelas ini di XML Anda. app: layout_behavior = "com.my.package.UserLockBottomSheetBehavior"
Steve

3
Dalam beberapa kasus, ini masih tidak berhasil, jika kami memiliki daftar di bagian lembaran bawah, masih menyeret
Deepak Joshi

1
@DeepakJoshi mungkin Anda memperluas RecyclerView dan menimpa beberapa metode seperti 'hasNestedScrollingParent', tapi saya tidak yakin
Vitalii Obideiko

74

periksa status dalam onStateChangedmetode setBottomSheetCallbackjika status BottomSheetBehavior.STATE_DRAGGINGkemudian ubah ke BottomSheetBehavior.STATE_EXPANDEDcara ini Anda dapat berhenti STATE_DRAGGINGoleh pengguna. seperti dibawah ini

final BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                }
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            }
        });

gunakan tombol untuk membuka tutup lembaran bawah seperti di bawah ini

fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (behavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {
                    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                } else {
                    behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                }
            }
        });

jangan gunakan setPeekHeight atauapp:behavior_peekHeight

dengan cara di atas Anda dapat mencapai tujuan Anda


1
Trik yang bagus. Tidak menyadarinya. Terima kasih. Dan juga, dapatkah Anda membantu dengan ini. Ketika saya menyuruhnya untuk diperluas pada awalnya, itu transparan dan saya bisa melihat tampilan di belakang, tapi saya tidak bisa berinteraksi sampai saya mengetuk EditText di SheetView sebelum membuatnya terlihat.
Tonespy

Saya membuatnya BottomSheet View match_parentdan setiap kali saya mencoba untuk memunculkannya di saya, Activitysaya perhatikan itu meluncur ke atas, tetapi tidak terlihat sampai saya mengetuknya EditTextyang memunculkan Keyboarddan membuatnya BottomSheet Viewterlihat
Tonespy

1
Saya mencoba ini, tetapi negara bagian akhirnya masuk STATE_SETTLING. Saya memiliki tombol untuk membuka dan menutup lembaran bawah, jika TERSEMBUNYI, saya perluas. Jika DIPERLUAS, saya menyembunyikannya. Karena macet di SETTLING, tombol saya tidak berfungsi setelah menyeret lembar bawah. Ada ide tentang itu?
Gokhan Arik

3
Solusi ini tidak dapat diandalkan; lembaran bawah menjadi buruk, seperti yang dikatakan Gokhan ... dan ketika dalam kondisi buruk itu, panggilan seperti memuat fragmen baru ke dalam lembaran hanya akan kosong.
Ray W

7
Ini tidak akan bekerja jika Anda memiliki tampilan gulungan bersarang di dalam lembar bawah
Rishabh Chandel

32

Baiklah, jadi jawaban yang diterima tidak berhasil untuk saya. Namun, jawaban Виталий Обидейко menginspirasi solusi akhir saya.

Pertama, saya membuat BottomSheetBehavior kustom berikut. Ini mengesampingkan semua metode yang melibatkan sentuhan, dan mengembalikan false (atau tidak melakukan apa pun) jika terkunci. Jika tidak, itu bertindak seperti BottomSheetBehavior normal. Ini menonaktifkan kemampuan pengguna untuk menyeret ke bawah, dan tidak memengaruhi pengubahan status dalam kode.

LockableBottomSheetBehavior.java

public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    private boolean mLocked = false;

    public LockableBottomSheetBehavior() {}

    public LockableBottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setLocked(boolean locked) {
        mLocked = locked;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onInterceptTouchEvent(parent, child, event);
        }

        return handled;
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onTouchEvent(parent, child, event);
        }

        return handled;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        }

        return handled;
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) {
        if (!mLocked) {
            super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        }
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
        if (!mLocked) {
            super.onStopNestedScroll(coordinatorLayout, child, target);
        }
    }

    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) {
        boolean handled = false;

        if (!mLocked) {
            handled = super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
        }

        return handled;

    }
}

Berikut contoh cara menggunakannya. Dalam kasus saya, saya membutuhkannya agar Lembaran Bawah terkunci saat diperluas.

activity_home.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|snap"
            app:titleEnabled="false"/>
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"/>
    </android.support.design.widget.AppBarLayout>

    <!-- Use layout_behavior to set your Behavior-->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager"
        app:layout_behavior="com.myapppackage.LockableBottomSheetBehavior"/>

</android.support.design.widget.CoordinatorLayout>

HomeActivity.java

public class HomeActivity extends AppCompatActivity {
    BottomSheetBehavior mBottomSheetBehavior;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        recyclerView.setAdapter(new SomeAdapter());

        mBottomSheetBehavior = BottomSheetBehavior.from(recyclerView);
        mBottomSheetBehavior.setBottomSheetCallback(new MyBottomSheetCallback());
    }

    class MyBottomSheetCallback extends BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_EXPANDED) {
                if (mBottomSheetBehavior instanceof LockableBottomSheetBehavior) {
                    ((LockableBottomSheetBehavior) mBottomSheetBehavior).setLocked(true);
                }
            }
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {}
    });
}

Semoga ini bisa membantu menjernihkan banyak kebingungan!


1
Bagus, itu jawaban terbaik bahwa kita dapat menghindari solusi dari keadaan ini yang menyebabkan melewatkan acara. Terima kasih.
Tấn Nguyên

@ James - Jawaban bagus tapi sekarang saya tidak bisa setPeekHeight (). Ada ide?
Adarsh ​​Yadav

Saya mencoba ini. itu berhasil untuk saya. terima kasih bro untuk menyelamatkan pantatku
Sup. Ia

1
Ini adalah solusi yang bagus, meskipun tidak diperbarui untuk hari ini. OnNestedPreScroll dan metode tertentu lainnya tidak digunakan lagi. Perlu memperbarui metode tersebut dan berfungsi dengan baik.
Ajay

4
Halo, ini tidak berfungsi pada BottomSheetDialogFragment, saya masih dapat menyeret lembar bawah
florian-do

23

Saya akhirnya menulis solusi untuk mengatasi kasus penggunaan penonaktifan pengguna secara dinamis ini, di mana BottomSheetBehavior disubkelas untuk menimpa onInterceptTouchEvent, dan untuk mengabaikannya ketika bendera khusus (dalam hal ini mAllowUserDragging) disetel ke false:

import android.content.Context;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class WABottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
    private boolean mAllowUserDragging = true;
    /**
     * Default constructor for instantiating BottomSheetBehaviors.
     */
    public WABottomSheetBehavior() {
        super();
    }

    /**
     * Default constructor for inflating BottomSheetBehaviors from layout.
     *
     * @param context The {@link Context}.
     * @param attrs   The {@link AttributeSet}.
     */
    public WABottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setAllowUserDragging(boolean allowUserDragging) {
        mAllowUserDragging = allowUserDragging;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (!mAllowUserDragging) {
            return false;
        }
        return super.onInterceptTouchEvent(parent, child, event);
    }
}

Dan dalam tata letak xml Anda:

    <FrameLayout
        android:id="@+id/bottom_sheet_frag_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:behavior_hideable="true"
        app:behavior_peekHeight="@dimen/bottom_sheet_peek_height"
        app:elevation="@dimen/bottom_sheet_elevation"
        app:layout_behavior="com.example.ray.WABottomSheetBehavior" />

Sejauh ini, ini adalah solusi yang berperilaku paling konsisten untuk menonaktifkan pengguna yang menyeret di Lembar Bawah sesuai permintaan.

Semua solusi lain yang mengandalkan pengaktifan panggilan setState lain dalam callback onStateChanged mengakibatkan BottomSheet menjadi status yang buruk, atau menyebabkan masalah UX yang signifikan (dalam kasus memposting panggilan setState dalam Runnable).

Semoga ini bisa membantu seseorang :)

sinar


4
Itu cukup rapi
Odys

3
@BeeingJk Alih-alih FrameLayout, gunakan NestedScrollView, dan setelbottomSheetFragContainer.setNestedScrollingEnabled(false);
AfzalivE

1
SOLVED: dengan menyetel callback CoordinatorLayout.Behavior behavior = layoutParams.getBehavior (); if (perilaku! = null && contoh perilaku BottomSheetBehavior) {((perilaku (BottomSheetBehavior)) .setBottomSheetCallback (mBottomSheetBehaviorCallback); }
LOG_TAG

4
Ini tidak cocok untukku! PS: Saya memiliki teks yang dapat digulir di lembar bawah
Thorvald Olavsen

6
Bagaimana Anda melemparkannya selama inisialisasi? Ini memberi saya peringatan WABottomSheetBehavior <View> behavior = (WABottomSheetBehavior) BottomSheetBehavior.from (sheetView);
Leo Droidcoder

8

Jawaban terlambat, tetapi, inilah yang berhasil bagi saya, yang sedikit berbeda dengan apa yang disarankan orang lain.

Anda dapat mencoba menyetel cancelableproperti ke false, yaitu

setCancelable(false);

lalu secara manual menangani kejadian di mana Anda ingin menutup dialog dalam setupDialogmetode.

@Override
public void setupDialog(final Dialog dialog, final int style) {

    // handle back button
    dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
        @Override
        public boolean onKey(final DialogInterface dialog, final int keyCode, final KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                dialog.dismiss();
            }
            return true;
        }
    });

    // handle touching outside of the dialog
    final View touchOutsideView = getDialog().getWindow().getDecorView().findViewById(android.support.design.R.id.touch_outside);
    touchOutsideView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View view) {
            dialog.dismiss();
        }
    });
}

Ini berfungsi dengan ListView di dalam fragmen dialog, di mana saya sedikit terjebak dengan solusi lain.


Solusi singkat yang bagus. Kepada siapa pun yang membaca ini, Anda (mungkin) menginginkan pemeriksaan tambahan untuk event.isCanceled()dan event.getAction() == MotionEvent.ACTION_UPsebelum menutup dialog - ini akan mencegah kesalahan klik memicu penutupan.
Eric Bachhuber

Terima kasih untuk ini. Ini adalah solusi paling sederhana untuk menonaktifkan penarikan.
AVJ

7

Jawaban yang diterima tidak berfungsi pada perangkat uji pertama yang saya gunakan. Dan pantulannya kembali tidak mulus. Tampaknya lebih baik menyetel status menjadi STATE_EXPANDED hanya setelah pengguna melepaskan penyeretan. Berikut ini adalah versi saya:

    final BottomSheetBehavior behavior = BottomSheetBehavior.from(findViewById(R.id.bottomSheet));
    behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState > BottomSheetBehavior.STATE_DRAGGING)
                bottomSheet.post(new Runnable() {
                    @Override public void run() {
                        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    }
                });
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        }
    });

1
Biarkan saya memberi tahu Anda masalah dengan membuangnya ke dalam runnable kecuali itu yang Anda inginkan. Anda tidak dapat menutupnya dengan tombol karena perlu diseret untuk menutupnya. Dan, itu akan selalu merespons penarikan, hanya saja itu akan mencegah pengguna menarik untuk menutup
Tonespy

7

Tambahkan kode ini ke objek BottomSheetBehavior . Menarik akan dinonaktifkan. Bekerja dengan baik untuk saya.

final BottomSheetBehavior behavior = BottomSheetBehavior.from((View) view.getParent());
    behavior.setHideable(false);
    behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {

      @Override
      public void onStateChanged(@NonNull View bottomSheet, int newState) {
        if (newState == BottomSheetBehavior.STATE_DRAGGING) {
          behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }

      }
      @Override
      public void onSlide(@NonNull View bottomSheet, float slideOffset) {

      }
});

1
Ini tidak menonaktifkan gesekan. Ini meruntuhkan lembaran bawah sepenuhnya.
Adam Hurwitz

7

Perilaku yang diharapkan:

  • BottomSheet tidak menutup saat drag-down
  • BottomSheet menutup jika disentuh di luar jendela dialog

Kode:

class MyBottomSheet : BottomSheetDialogFragment () {

   override fun onActivityCreated(savedInstanceState: Bundle?) {
       super.onActivityCreated(savedInstanceState)
       disableBottomSheetDraggableBehavior()
   }

   private fun disableBottomSheetDraggableBehavior() {
      this.isCancelable = false
      this.dialog?.setCanceledOnTouchOutside(true)
   }

 }

Untuk beberapa alasan, saya tidak bisa menutup dialog yang menyentuh di luar, tetapi berfungsi untuk menonaktifkan seret
Gastón Saillén

5

Untuk mengunci BottomSheet dan menghindari pengguna untuk menggeseknya, inilah yang saya lakukan

public void showBottomSheet() {
    bsb.setHideable(false);
    bsb.setState(BottomSheetBehavior.STATE_EXPANDED);
}

public void hideBottomSheet() {
    bsb.setHideable(true);
    bsb.setState(BottomSheetBehavior.STATE_COLLAPSED);
}

Ini bekerja cukup baik untuk saya.


Solusi ini menarik tetapi secara aneh menyebabkan lembaran bawah muncul dari atas layar, bukan dari bawah! Namun itu menghilang dengan cara normal. Ini sangat Star Trek.
Tunga

Saya perlu membuat modifikasi pemandangan dan sebagai gantinya menggunakan BottomSheetBehavior.STATE_HIDDEN. Dalam kasus seperti itu, Anda juga tidak boleh menelepon setPeekHeight(). Ini jauh lebih mudah daripada solusi lain di sini.
HolySamosa

5

Cara mudah untuk mengunci menyeret adalah setPeekHeight sama dengan ketinggian tampilan. Sebagai contoh:

private LinearLayout bottomSheet;
private BottomSheetBehavior bottomBehavior;

@Override
public void onResume() {
    super.onResume();
    bottomBehavior = BottomSheetBehavior.from((bottomSheet);
    bottomBehavior.setPeekHeight(bottomSheet.getHeight());
    bottomBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}

4

Sampel dengan BottomSheetDialogFragment. Ini bekerja dengan sempurna.

Edit 09/04/2020: Mengganti depresiasi setBottomSheetCallback()denganaddBottomSheetCallback()

class FragMenuBDrawer : BottomSheetDialogFragment() {

    ...

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog

        dialog.setOnShowListener {
            val bottomSheet = (it as BottomSheetDialog).findViewById<View>(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout?
            val behavior = BottomSheetBehavior.from(bottomSheet!!)
            behavior.state = BottomSheetBehavior.STATE_EXPANDED

            behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
                override fun onStateChanged(bottomSheet: View, newState: Int) {
                    if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                        behavior.state = BottomSheetBehavior.STATE_EXPANDED
                    }
                }

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

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

    ...
}

3

Anda tidak perlu memblokir semua acara saat lembar bawah dinonaktifkan. Anda hanya dapat memblokir acara ACTION_MOVE. Itulah mengapa gunakan perilaku lembar bawah khusus seperti ini

public class BottomSheetBehaviorWithDisabledState<V extends View> extends BottomSheetBehavior<V> {
    private boolean enable = true;

    /**
     * Default constructor for instantiating BottomSheetBehaviors.
     */
    public BottomSheetBehaviorWithDisabledState() {
        super();
    }

    /**
     * Default constructor for inflating BottomSheetBehaviors from layout.
     *
     * @param context The {@link Context}.
     * @param attrs   The {@link AttributeSet}.
     */
    public BottomSheetBehaviorWithDisabledState(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setEnable(boolean enable){
        this.enable = enable;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (!enable && event.getAction() == MotionEvent.ACTION_MOVE){
            return false;
        }
        return super.onInterceptTouchEvent(parent, child, event);
    }
}

Bagaimana Anda menggunakan kelas ini? Saya mendapatkan IllegalArgumentException: Tampilan tidak terkait dengan BottomSheetBehavior
user3144836

3

Berikut adalah versi kerja dari solusi teratas di Kotlin:

import android.support.design.widget.BottomSheetBehavior
import android.support.design.widget.CoordinatorLayout
import android.view.MotionEvent
import android.view.View

class CustomBottomSheetBehavior<V : View> : BottomSheetBehavior<V>() {

    @Suppress("UNCHECKED_CAST")
    companion object {
        fun <V : View> from(view: V): CustomBottomSheetBehavior<V> {
            val params = view.layoutParams as? CoordinatorLayout.LayoutParams ?:
                throw IllegalArgumentException("The view is not a child of CoordinatorLayout")
                params.behavior as? BottomSheetBehavior<V> ?:
                    throw IllegalArgumentException("The view is not associated with BottomSheetBehavior")
                params.behavior = CustomBottomSheetBehavior<V>()
            return params.behavior as CustomBottomSheetBehavior<V>
        }
    }

    override fun onInterceptTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        return false
    }

    override fun onTouchEvent(parent: CoordinatorLayout, child: V, event: MotionEvent): Boolean {
        return false
    }

    override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, directTargetChild: View, target: View, axes: Int, type: Int): Boolean {
        return false
    }

    override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {}

    override fun onStopNestedScroll(coordinatorLayout: CoordinatorLayout, child: V, target: View, type: Int) {}

    override fun onNestedPreFling(coordinatorLayout: CoordinatorLayout, child: V, target: View, velocityX: Float, velocityY: Float): Boolean {
        return false
    }
}

Kemudian kapan pun Anda ingin menggunakan:

val bottomSheetBehavior by lazy {
    CustomBottomSheetBehavior.from(bottom_sheet_main)
}

Ini bottom_sheet_mainadalah tampilan sebenarnya menggunakan Kotlin Android Extensions .


3

setel bottomSheet onClickListener ke null.

bottomSheet.setOnClickListener(null);

baris ini menonaktifkan semua tindakan tentang bottomSheet saja dan tidak berpengaruh pada tampilan dalam.


1
Ini menyebabkan animasi yang tidak terduga saat Lembar Bawah berusaha untuk menutup.
Adam Hurwitz

3
implementation 'com.google.android.material:material:1.2.0-alpha05'

Anda dapat menonaktifkan menyeret BottomSheet seperti ini.

import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED

//another code

this.bottomSheetBehavior = BottomSheetBehavior.from(view)
this.bottomSheetBehavior.state = STATE_EXPANDED
this.bottomSheetBehavior.isDraggable = false // disable dragging

//another code
this.bottomSheetbehavior.isDraggable = true //draggable

(kotlin), saya harap jawaban ini dapat menyelesaikan masalah Anda.


1
Versi alfa ini berperilaku gila. Saya tidak merekomendasikan :(
Adam Styrc

2

Saya telah menemukan solusi yang luar biasa. Masalah awal adalah ketika bottomSheet akan menjadi status HIDDEN kemudian tidak muncul di bottomSheetDialog.show (). Tapi saya ingin dialog terlihat pada metode show () dan juga ingin memungkinkan pengguna untuk menggeseknya ke bawah sehingga terasa seperti lembaran bawah. Di bawah ini yang saya lakukan ..

    BottomSheetDialog itemTypeDialog = new BottomSheetDialog(this);
    View bottomSheetView = getLayoutInflater().inflate(R.layout.dialog_bottomsheet, null);
    itemTypeDialog.setContentView(bottomSheetView);
    BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from((View) bottomSheetView.getParent());
    bottomSheetBehavior.setBottomSheetCallback(bottomSheetCallback); // You can also attach the listener here itself.

    BottomSheetBehavior.BottomSheetCallback bottomSheetCallback =  new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        Log.d(TAG, "BottomSheetCallback: " + newState);
        if (newState == BottomSheetBehavior.STATE_HIDDEN) {
            bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
            itemTypeDialog.dismiss();
        } 
    }

    @Override
    public void onSlide(@NonNull View bottomSheet, float slideOffset) {

    }
};

ini adalah jawaban yang sempurna
Vivek Kumar Srivastava

2
  1. Menyalin BottomSheetDialog ke proyek Anda dan ganti namanya menjadiMyBottomSheetDialog
  2. Menambahkan getBottomSheetBehavior keMyBottomSheetDialog
  3. menggunakan MyBottomSheetDialog sebagai gantinyaBottomSheetDialog
  4. bottomSheetBehavior.setBottomSheetCallback

kode seperti ini

public class MyBottomSheetDialog extends AppCompatDialog {

    // some code

    public BottomSheetBehavior<FrameLayout> getBottomSheetBehavior() {
        return mBehavior;
    }

    // more code

dalam kode Anda

    final BottomSheetBehavior<FrameLayout> bottomSheetBehavior = myBottomSheetDialog.getBottomSheetBehavior();
    bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
        @Override
        public void onStateChanged(@NonNull View bottomSheet, int newState) {
            if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            }
        }

        @Override
        public void onSlide(@NonNull View bottomSheet, float slideOffset) {

        }

2

Ini pada dasarnya adalah versi kotlin dari jawaban yang benar di atas:

    class LockedBottomSheetBehavior<V : View>(context: Context, attrs: AttributeSet) :
        BottomSheetBehavior<V>(context, attrs) {

    companion object {
        fun <V : View> from(view: V): LockedBottomSheetBehavior<*> {
            val params = view.layoutParams as? CoordinatorLayout.LayoutParams
                    ?: throw IllegalArgumentException("The view is not a child of CoordinatorLayout")
            return params.behavior as? LockedBottomSheetBehavior<*>
                    ?: throw IllegalArgumentException(
                            "The view is not associated with BottomSheetBehavior")
        }
    }

    override fun onInterceptTouchEvent(
            parent: CoordinatorLayout,
            child: V, event: MotionEvent
    ) = false

    override fun onTouchEvent(
            parent: CoordinatorLayout,
            child: V,
            event: MotionEvent
    ) = false

    override fun onStartNestedScroll(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            directTargetChild: View,
            target: View,
            axes: Int,
            type: Int) = false

    override fun onNestedPreScroll(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            target: View,
            dx: Int,
            dy: Int,
            consumed: IntArray,
            type: Int) {
    }

    override fun onStopNestedScroll(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            target: View,
            type: Int) {
    }

    override fun onNestedPreFling(
            coordinatorLayout: CoordinatorLayout,
            child: V,
            target: View,
            velocityX: Float,
            velocityY: Float
    ) = false
}

Bagaimana Anda menggunakan kelas ini? Saya mendapatkan IllegalArgumentException: Tampilan tidak terkait dengan BottomSheetBehavior
user3144836

1
app: layout_behavior = "UserLockBottomSheetBehavior"> dalam xml dan kemudian dalam kode Anda melakukan hal berikut. // dapatkan tampilan lembar terbawah LinearLayout llBottomSheet = (LinearLayout) findViewById (R.id.bottom_sheet); // init perilaku lembar bawah BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from (llBottomSheet);
Jamal

2

Dengan 'com.google.android.material:material:1.2.0-alpha06'

Sangat cocok dengan NestedScrollView danRecyclerView

Kode contoh:

    LinearLayout contentLayout = findViewById(R.id.contentLayout);
    sheetBehavior = BottomSheetBehavior.from(contentLayout);
    sheetBehavior.setDraggable(false);

1

Coba ini.

1) Buat lembar bawah dan deklarasikan variabel di kelas java Anda seperti

private BottomSheetBehavior sheetBehavior;

2) sheetBehavior = BottomSheetBehavior.from(bottomSheet);

3) Di fungsi panggilan balik lembar bawah tambahkan baris berikut.

sheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                switch (newState) {
                    case BottomSheetBehavior.STATE_HIDDEN:
                        Log.d(TAG, "--------------  STATE_HIDDEN");
                        break;
                    case BottomSheetBehavior.STATE_EXPANDED: {
                        Log.d(TAG, "--------------  STATE_EXPANDED");
                    }
                    break;
                    case BottomSheetBehavior.STATE_COLLAPSED: {
                        Log.d(TAG, "--------------  STATE_COLLAPSED");
                    }
                    break;
                    case BottomSheetBehavior.STATE_DRAGGING:
                        sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                        break;
                    case BottomSheetBehavior.STATE_SETTLING:
                        Log.d(TAG, "--------------  STATE_SETTLING");
                        break;
                }
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {

            }
        });

1

Awalnya, saya hanya ingin mengucapkan terima kasih kepada kalian semua yang mencoba memberikan jawaban. Saya hanya menulis jawaban ini dengan memecahkan masalah ini seperti yang saya inginkan. Saya akan menjelaskan bagaimana saya melakukannya selangkah demi selangkah dengan mengambil bantuan dari sini.

Visualisasi: Setelah mengklik Tombol, Show BottomSheetAnda akan melihat layar kedua . Sekarang Anda akan melihat bahwa BottomSheet baru saja dikunci untuk menyeret . Tetapi jika Anda mengklik Daftar Negara , BottomSheet akan bersembunyi. Ini adalah deskripsinya sekarang mari kita gali Kode.

  • Pertama-tama, tambahkan pustaka dukungan desain ke file build.gradle Anda :

    implementasi 'com.android.support:design:28.0.0'

  • UserLockBottomSheetBehavior.java : Kredit: James Davis (Thanks Man)

public class UserLockBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    public UserLockBottomSheetBehavior() {
        super();
    }

    public UserLockBottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        return false;
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        return false;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) {
        return false;
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) {
    }

    @Override
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
    }

    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) {
        return false;
    }

}
  • bottomsheet.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bottomSheet"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical"
    android:orientation="vertical"
    app:behavior_hideable="true"
    app:layout_behavior="com.samsolution.custombottomsheet.UserLockBottomSheetBehavior">

 <RelativeLayout
     android:id="@+id/minimizeLayout"
     android:background="@color/colorPrimary"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/actionBarSize">

     <TextView
         android:layout_centerHorizontal="true"
         android:padding="16dp"
         android:layout_width="wrap_content"
         android:layout_height="?android:attr/actionBarSize"
         android:gravity="center_horizontal|center"
         android:text="Country List"
         android:textColor="#FFFFFF"
         android:textStyle="bold" />
 </RelativeLayout>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ListView
            android:id="@+id/homeCountryList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v7.widget.CardView>

</LinearLayout>
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="center"
        android:onClick="showCountryListFromBottomSheet">

        <Button
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_red_light"
            android:onClick="showCountryListFromBottomSheet"
            android:padding="16dp"
            android:text="Show BottomSheet"
            android:textAllCaps="false"
            android:textColor="#ffffff" />

    </LinearLayout>

    <include layout="@layout/bootomsheet" />

</android.support.design.widget.CoordinatorLayout>
  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    private BottomSheetBehavior<LinearLayout> bottomSheetBehavior;                                  // BottomSheet Instance
    LinearLayout bottomsheetlayout;
    String[] list = {"A", "B", "C", "D", "A", "B", "C", "D","A", "B", "C", "D","A", "B", "C", "D","A", "B", "C", "D"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bottomsheetlayout = findViewById(R.id.bottomSheet);
        bottomSheetBehavior = BottomSheetBehavior.from(bottomsheetlayout);

        ListView listView = findViewById(R.id.homeCountryList);
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,list);
        listView.setAdapter(adapter);

        bottomSheetHide();                                                                          //BottomSheet get hide first time

        RelativeLayout minimizeLayoutIV;                                                            // It will hide the bottomSheet Layout
        minimizeLayoutIV = findViewById(R.id.minimizeLayout);
        minimizeLayoutIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               bottomSheetHide();
            }
        });
    }

    public void showCountryListFromBottomSheet(View view) {
        bottomSheetBehavior.setHideable(false);
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }

    public void bottomSheetHide(){
        bottomSheetBehavior.setHideable(true);
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
    }
}

Layar Pertama Layar Kedua


1

Solusi dari jawaban yang diterima sebagian besar berhasil untuk saya, tetapi dengan satu masalah: pandangan, yang berada di belakang tampilan lembar bawah, mulai bereaksi pada peristiwa sentuh, jika peristiwa sentuhan terjadi di area lembaran bawah, yang bebas dari pandangan anak. Dengan kata lain, seperti yang terlihat pada gambar di bawah ini, ketika pengguna menyelipkan jari ke dalam lembaran bawah, peta mulai bereaksi.

area sentuh lembaran bawah

Untuk memperbaiki masalah ini, saya telah memodifikasi onInterceptTouchEventmetode dengan mengatur touchListenertampilan lembar bawah (kode lainnya tetap sama seperti dalam solusi yang diterima).

override fun onInterceptTouchEvent(
        parent: CoordinatorLayout,
        child: V, event: MotionEvent
    ): Boolean {
        child.setOnTouchListener { v, event ->
            true
        }
        return false
    }

0

Menyesuaikan peakHeightnilai berhasil bagi saya.

Saya mengatur peakheight sebagai tinggi bottomsheet jika diperluas.

    private val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
    override fun onSlide(bottomSheet: View, slideOffset: Float) {

    }

    override fun onStateChanged(bottomSheet: View, newState: Int) {
        if (newState == BottomSheetBehavior.STATE_EXPANDED)
            bottomSheetBehavior.peekHeight = bottomSheet.height
    }
}

1
Ini tidak ideal karena dapat menyebabkan animasi yang tidak terduga.
Adam Hurwitz

Dalam kasus saya. Itu tidak menyebabkan masalah animasi sama sekali. Itu hanya tidak bergerak setelah kartu diperluas. Ini tidak ideal tetapi berhasil seperti yang diharapkan!
pz64_

Menarik, bisa jadi itu masalahnya. Saya menyelesaikan masalah dengan Lembar Bawah saya menutup secara tidak terduga dengan mengatur Toolbar CollapsingToolbarLayout menjadi Tak Terlihat atau Hilang saat Lembaran Bawah terbuka. Interaksi sentuh yang terkait dengan Toolbar meskipun itu di bawah menyebabkan Lembaran Bawah menutup secara tidak terduga. Masalahnya sudah diperbaiki sekarang.
Adam Hurwitz

0
    LayoutInflater inflater = LayoutInflater.from(context);
            View view = inflater.inflate(R.layout.bottomsheet_view_profile_image, null);
            BottomSheetDialog dialog = new BottomSheetDialog(context);
            dialog.setContentView(view);
            dialog.setCancelable(false);


            BottomSheetBehavior behavior = BottomSheetBehavior
                    .from(((View) view.getParent()));
            behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                @Override
                public void onStateChanged(@NonNull View bottomSheet, int newState) {
                    if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    }
                }

                @Override
                public void onSlide(@NonNull View bottomSheet, float slideOffset) {
                }
            });
            behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            behavior.setSkipCollapsed(true);
            dialog.show();

0

ini adalah hasil pertama di google jadi saya yakin adil untuk meletakkan solusi sederhana di sini:

   private fun disableDragToDismiss() {
    if (dialog is BottomSheetDialog) {
        val bsDialog = dialog as BottomSheetDialog
        bsDialog.behavior.isHideable = false
    } else {
        Log.d(TAG, " BottomSheetDialog with dialog that is not BottomSheetDialog")
    }
}

dan dari sekadar memanggilnya dari onCreateView()dalam BottomSheetDialogFragmentimplementasi


0

Saya memiliki masalah yang sama BottomSheetDialogFragmentdan menerapkan banyak solusi menggunakan behaviordari dialogtetapi tidak ada yang menyelesaikan masalah saya dan kemudian saya menyelesaikannya tetapi mengatur setCancelable(false);pada saat inisialisasi dialog.

DialogEndRide dialogCompleteRide = new DialogEndRide();
dialogCompleteRide.setCancelable(false);
dialogCompleteRide.show(getChildFragmentManager(), "");

Ini akan menonaktifkan gerakan aktif BottomSheetDialogFragmentdan Anda dapat menutup secara dialogterprogram dengan menggunakan dismiss();fungsi.


-1

Saya memiliki masalah yang sama, saya menyelesaikannya dengan kode. Ini tidak akan mengizinkan pengguna untuk menyeret lembar bawah. Anda perlu menangani status secara terprogram.

 mBottomSheetBehavior.isDraggable = false

-2

Cukup gunakan: bottomSheet.dismissOnDraggingDownSheet = false

Disalin dari situs Material.io:

let viewController: ViewController = ViewController() let bottomSheet: MDCBottomSheetController = MDCBottomSheetController(contentViewController: viewController)

// **** Baris ini mencegah penutupan dengan menyeret bottomSheet ****

bottomSheet.dismissOnDraggingDownSheet = false

present(bottomSheet, animated: true, completion: nil)


Ini untuk iOS di sini bukan Android
Back Packer
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.