禁用用户在底部工作表上的拖动

我试图禁用用户在 BottomSheet上拖动。我想关闭它的原因有两点。1.它阻止了 ListView向下滚动,2。我不希望用户解散使用拖动,但与一个按钮上的 BottomSheetView。这就是我所做的

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

底部的 SheetLayout

    <?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>

114865 次浏览

setBottomSheetCallbackonStateChanged方法中检查状态,如果状态是 BottomSheetBehavior.STATE_DRAGGING,那么将其改为 BottomSheetBehavior.STATE_EXPANDED,这样用户就可以停止 STATE_DRAGGING。比如下面

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

使用按钮打开如下关闭底板

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

不要使用 setPeekHeightapp:behavior_peekHeight

by above way you can reach your goal

接受的答案在我使用的第一个测试设备上不起作用。反弹并不平稳。只有在用户释放拖动之后,才将状态设置为 STATE _ EXPANDED 似乎更好。以下是我的版本:

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

最后,我写了一个解决方案来处理这个动态禁用用户拖动的用例,其中 BottomSheetBehavior 被子类化以覆盖 onInterceptTouchEvent,并在自定义标志(在本例中为 mAllowUserDrags)设置为 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);
}
}

在您的布局 xml 中:

    <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" />

So far, this is the most consistently behaving solution for disabling user dragging on the Bottom Sheet on demand.

所有其他依赖于在 onStateChanged 回调中触发另一个 setState 调用的解决方案都会导致 BottomSheet 进入一个糟糕的状态,或者导致重大的用户体验问题(在使用 Runnable 发布 setState 调用的情况下)。

希望这对某些人有所帮助:)

为了锁定底部表格,并避免用户刷出这是我所做的

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


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

我觉得挺好的。

它现在可能已经不再相关,但我将把它留在这里:

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
}
}
}

并在 xml 文件中使用它:

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

它禁用所有用户操作,当您只希望以编程方式控制 BottomSheet 时可以使用它。

好吧,这个被接受的答案对我来说不起作用。然而,答案启发了我最终的解决方案。

首先,我创建了以下自定义 BottomSheetBehavior。它覆盖所有涉及触摸的方法,如果它被锁定,则返回 false (或者什么也没做)。否则,它的行为就像一个正常的 BottomSheetBehavior。这将禁用用户向下拖动的能力,并且不影响更改代码中的状态。

行为

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;


}
}

这里有一个如何使用它的例子。在我的情况下,我需要它,所以底部表格锁定时,展开。

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

希望这有助于消除很多的困惑!

我已经找到了惊人的解决方案。最初的问题是,一旦 bottomSheet 进入 HIDDEN 状态,那么它就不会出现在 bottomSheetDialog.show ()中。 但是我想让 show ()方法中的对话框可见,并且还想让用户能够向下滑动它,使它看起来像底部的工作表。下面是我所做的。.

    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) {


}
};

将此代码添加到 页底行为对象。将禁用拖动。 我觉得挺好的。

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) {


}
});

当底部工作表被禁用时,您不需要阻止所有事件。只能阻止 ACTION _ MOVE 事件。这就是为什么要使用这样的自定义底部表行为

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

回答晚了,但是,这是什么工作对我来说,这是有点不同于其他人的建议。

您可以尝试将 cancelable属性设置为 false,即。

setCancelable(false);

然后手动处理您希望在 setupDialog方法中关闭对话框的事件。

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

这适用于对话框片段中的 ListView,我在这里遇到了一些其他解决方案的问题。

锁定拖动的简单方法是 setPeekHeight 和 view height 相同。 例如:

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);
}
  1. BottomSheetDialog复制到项目并将其重命名为 MyBottomSheetDialog
  2. getBottomSheetBehavior加到 MyBottomSheetDialog
  3. 使用 MyBottomSheetDialog代替 BottomSheetDialog
  4. 回调

这样的代码

public class MyBottomSheetDialog extends AppCompatDialog {


// some code


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


// more code

在你的代码里

    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) {


}

这基本上就是顶部正确答案的 Kotlin 版本:

    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
}

Here is a working version of the top solution in 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
}
}

然后无论什么时候你想用:

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

bottom_sheet_main是使用 Kotlin Android Extensions的实际视图。

将 bottomSheetonClickListener 设置为 null。

bottomSheet.setOnClickListener(null);

此行仅禁用关于 bottomSheet 的所有操作,并且不影响内部视图。

调整 peakHeight值对我有用。

如果展开的话,我将峰值高度设置为底纸的高度。

    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)创建底部工作表并在 Java 类中声明变量,如

private BottomSheetBehavior sheetBehavior;

2) sheetBehavior = BottomSheetBehavior.from(bottomSheet);

3)在底部的工作表回调函数中添加以下行。

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) {


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

我在 BottomSheetDialogFragment中遇到了同样的问题,并且使用 dialogbehavior应用了很多解决方案,但是没有一个解决了我的问题,然后我解决了它,但是在 dialog初始化的时候设置了 setCancelable(false);

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

这将在 BottomSheetDialogFragment上禁用手势,您可以通过使用 dismiss();函数以编程方式关闭 dialog

首先,我想感谢你们所有试图给出答案的人。我只是通过解决这个问题来写出我想要的答案。我将从这里开始一步一步地描述我是如何做到这一点的。

可视化: 单击按钮 Show BottomSheet后,您将看到 第二幕。现在,您将看到 底纸刚刚为 dragging锁定。但是如果你点击的 国家名单底纸将隐藏。这就是现在的描述,让我们深入研究代码。

  • 首先,将设计支持库添加到 建造,分级文件中:

    实现‘ com.android.support: design: 28.0.0’

  • UserLockBottomSheetBehavior or.java : 来源: 詹姆斯 · 戴维斯(谢谢)

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


First Screen Second Screen

一个带有 BottomSheetDialog 片段的示例。

编辑09/04/2020: addBottomSheetCallback()代替折旧的 setBottomSheetCallback()

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
}


...
}

预期行为:

  • BottomSheet does not close on drag-down
  • 如果在对话框窗口外触摸,则 BottomSheet 关闭

密码:

class MyBottomSheet : BottomSheetDialogFragment () {


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


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


}

这是谷歌的第一个结果,所以我相信它的唯一公平的是把简单的解决方案放在这里:

   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")
}
}

而不仅仅是在 BottomSheetDialogFragment实现中从 onCreateView()调用它

来自 接受的答案的解决方案大部分对我有效,但是有一个问题: 视图,位于底部页面视图的后面,开始对触摸事件做出反应,如果触摸事件发生在底部页面的区域,这是免费的子视图。 换句话说,你可以在下面的图片中看到,当用户将手指滑入底部的纸张时,地图就开始对其做出反应。

bottom sheet touch area

为了解决这个问题,我修改了 onInterceptTouchEvent方法,在底部工作表视图中设置了 touchListener(其余代码与已接受的解决方案中的代码相同)。

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

简单使用: bottomSheet.dismissOnDraggingDownSheet = false

复制自 Matrial.io 网站:

让 viewController: ViewController = ViewController () Let bottomSheet: MDCBottomSheetController = MDCBottomSheetController (contentViewController: viewController)

// **** This line prevents dismiss by dragging bottomSheet ****

bottomSheet.dismissOnDraggingDownSheet = false

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

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

您可以像这样禁用拖动底纸。

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = BottomSheetDialog(requireContext(), theme)
dialog.setOnShowListener {
setBottomSheetExpanded(dialog)
}
return dialog
}


open fun setBottomSheetExpanded(bottomSheetDialog: BottomSheetDialog) {
val bottomSheet =
bottomSheetDialog.findViewById<View>(R.id.design_bottom_sheet) as FrameLayout?
bottomSheet?.let {
val behavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(bottomSheet)
val layoutParams = bottomSheet.layoutParams
bottomSheet.layoutParams = layoutParams
behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.isDraggable = false / true
}


}

编辑)库已更新! 您可以使用新的库版本

implementation 'com.google.android.material:material:1.4.0'

这些例子都是相同的,祝你好运,代码也很好

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

适用于 NestedScrollViewRecyclerView

示例代码:

    LinearLayout contentLayout = findViewById(R.id.contentLayout);
sheetBehavior = BottomSheetBehavior.from(contentLayout);
sheetBehavior.setDraggable(false);
BottomSheetDialog calcDialog = new BottomSheetDialog(this);
View view = getLayoutInflater().inflate(R.layout.bottom_sheet_calc, null);
calcDialog.setContentView(view);
calcDialog.setCancelable(false);

你可以用 android.app.Dialog代替 WindowGravity.BOTTOM:

Dialog dialog = new Dialog(this);
dialog.getWindow().getAttributes().gravity = Gravity.BOTTOM;
dialog.show();

如果你想动画像在 BottomSheetDialog添加到您的 styles.xml

<style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
<item name="bottomSheetStyle">@style/bottomSheetStyleWrapper</item>
</style>


<style name="bottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal">
<item name="android:background">@android:color/transparent</item>
</style>

以及 Java 代码:

Dialog dialog = new Dialog(this, R.style.BottomSheetDialog);

仅供参考: 遵循资料用户界面的最佳实践,您必须创建自己的类,扩展 BottomSheetDialogFragment。 在这个类中,您可以重写 onStart 方法并在其中添加以下代码:

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


behavior.state = BottomSheetBehavior.STATE_EXPANDED
behavior.isDraggable = false
}

对我来说很有效

onCreateView函数中调用这个方法,使底层工作表不可撤销、不可取消和不可拖动(使用适用于您的用例的任何东西) :

    private fun disableDialog() {
this.dialog?.let { bottomSheet ->
// Disable dismiss on outside touch
bottomSheet.setCanceledOnTouchOutside(false)


// Hide the cancel button
bottomSheet.setCancelable(false)


// Disable back key press
bottomSheet.setOnKeyListener { _, keyCode, _ ->
keyCode == KeyEvent.KEYCODE_BACK
}


// Make it non-draggable
bottomSheet.setOnShowListener {
(it as BottomSheetDialog).behavior.setDraggable(false)
}
}
}

防止用户拖动底部工作表以解除/打开

    bottomSheetDialog_OverView = new BottomSheetDialog(context);
View dialogView = View.inflate(context, R.layout.dialog_overview, null);
bottomSheetDialog_OverView.getBehavior().setDraggable(false);

对于使用 BottomSheetDialog 片段()扩展的 Dialogs,只需使用以下内容

禁用滑动功能

if (dialog?.window != null) {
dialog!!.setCancelable(false)
}

启用滑动特性

if (dialog?.window != null) {
dialog!!.setCancelable(true)
}

val behavior = BottomSheetBehavior.from(bottomSheet)
behaviour.isDraggable = false

private fun bottomSheetBehaviour(bottomSheet: BottomSheetDialog) {
bottomSheet.setOnShowListener {


val bottomSheetDialog = it as BottomSheetDialog
val parentLayout =
bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
parentLayout?.let { parentView ->
val behaviour = BottomSheetBehavior.from(parentView)
setupFullHeight(parentView)
behaviour.isDraggable = false
behaviour.peekHeight = parentView.height
behaviour.state = BottomSheetBehavior.STATE_EXPANDED
}
bottomSheet.setCancelable(false)
}
}
  • PeekHeight = ParentView.height
  • SetCancelable (false)

上面的两行代码帮助我修复 BottomSheetDialogFragment 的行为