android - redes - informacion mediatica
Deshabilitar al usuario arrastrando en la hoja inferior (22)
-
Copie
BottomSheetDialog
a su proyecto y cambie el nombre aMyBottomSheetDialog
-
agregar
getBottomSheetBehavior
aMyBottomSheetDialog
-
use
MyBottomSheetDialog
lugar deBottomSheetDialog
- bottomSheetBehavior.setBottomSheetCallback
código como este
public class MyBottomSheetDialog extends AppCompatDialog {
// some code
public BottomSheetBehavior<FrameLayout> getBottomSheetBehavior() {
return mBehavior;
}
// more code
en tu código
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) {
}
Estoy tratando de deshabilitar el arrastre del usuario en
BottomSheet
.
La razón por la que quiero desactivar es dos cosas.
1.
ListView
desplace hacia abajo, 2. No quiero que los usuarios descarten mediante el arrastre pero con un botón en
BottomSheetView
.
Esto es lo que he hecho
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>
En caso de que alguien pueda ayudar en el futuro, la mejor solución para mí fue crear un nuevo estilo y asignar:
<style name="BottomSheetDialogTheme" parent="BaseBottomSheetDialog">
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
y luego dentro de la clase BottomSheetDialogFragment anuló el método:
override fun getTheme(): Int = R.style.BottomSheetDialogTheme
Una muestra con BottomSheetDialogFragment. Funciona perfectamente
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.setBottomSheetCallback(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
}
...
}
Agregue este código al objeto BottomSheetBehavior . El arrastre se desactivará. Funciona bien para mi.
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) {
}
});
Ahora ya no puede ser relevante, pero lo dejaré aquí:
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
}
}
}
Y úsalo en tu archivo xml:
app:layout_behavior="com.your.package.LockableBottomSheetBehavior"
Deshabilita todas las acciones de los usuarios, se puede usar cuando desee controlar BottomSheet solo mediante programación.
Ajustar el valor de
peakHeight
funcionó para mí.
Establezco la altura máxima como la altura de la hoja inferior si se expande.
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
}
}
Al principio, solo quiero agradecer a todos los que intentaron dar una respuesta. Solo estoy escribiendo esta respuesta resolviendo este problema como quiero. Voy a describir cómo lo hago paso a paso tomando ayuda de aquí.
Visualización:
después de hacer clic en el botón
Show BottomSheet
, verá la
segunda pantalla
.
Ahora verá que
BottomSheet
está bloqueado para
arrastrarlo
.
Pero si hace clic en la
Lista de países,
la
Hoja inferior
se ocultará.
Esta fue la descripción ahora vamos a profundizar en el Código.
-
Al principio, agregue la biblioteca de soporte de diseño a su archivo build.gradle :
implementación ''com.android.support:design:28.0.0''
-
UserLockBottomSheetBehavior.java : Crédito: (Gracias, hombre)
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);
}
}
Aquí hay una versión funcional de la solución superior en 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
}
}
Entonces, cuando quieras usar:
val bottomSheetBehavior by lazy {
CustomBottomSheetBehavior.from(bottom_sheet_main)
}
bottom_sheet_main
es la vista real que usa
Kotlin Android Extensions
.
Esta es básicamente la versión kotlin de la respuesta correcta en la parte superior:
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
}
He encontrado una solución asombrosa. El problema inicial fue una vez que bottomSheet iba a estado OCULTADO y luego no se mostraba en bottomSheetDialog.show (). Pero quería que el cuadro de diálogo fuera visible en el método show () y también quería permitir que el usuario lo deslice hacia abajo para que se sienta como la hoja inferior. A continuación se muestra lo que hice.
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) {
}
};
La forma fácil de bloquear el arrastre es establecer PeekHeight igual que la altura de la vista. Por ejemplo:
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);
}
La respuesta aceptada no funciona en el primer dispositivo de prueba que uso. Y el rebote no es suave. Parece mejor establecer el estado en STATE_EXPANDED solo después de que un usuario suelte el arrastre. La siguiente es mi versión:
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) {
}
});
Muy bien, entonces la respuesta aceptada no funcionó para mí. Sin embargo, la respuesta de Виталий Обидейко inspiró mi solución final.
Primero, creé el siguiente BottomSheetBehavior personalizado. Anula todos los métodos que involucran el tacto y devuelve falso (o no hizo nada) si está bloqueado. De lo contrario, actúa como un BottomSheetBehavior normal. Esto deshabilita la capacidad del usuario para arrastrar hacia abajo y no afecta el cambio de estado en el código.
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;
}
}
Aquí hay un ejemplo de cómo usarlo. En mi caso, lo necesitaba para que la hoja inferior se bloqueara cuando se expandía.
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) {}
});
}
¡Espero que esto ayude a aclarar mucha confusión!
No necesita bloquear todos los eventos cuando la hoja inferior está deshabilitada. Solo puede bloquear el evento ACTION_MOVE. Es por eso que use un comportamiento de hoja inferior personalizado como este
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);
}
}
Para bloquear el BottomSheet y evitar que el usuario lo deslice, esto es lo que hice
public void showBottomSheet() {
bsb.setHideable(false);
bsb.setState(BottomSheetBehavior.STATE_EXPANDED);
}
public void hideBottomSheet() {
bsb.setHideable(true);
bsb.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
Funciona bastante bien para mi.
Prueba esto.
1) Cree una hoja inferior y declare la variable en su clase java como
private BottomSheetBehavior sheetBehavior;
2)
sheetBehavior = BottomSheetBehavior.from(bottomSheet);
3) En la función de devolución de llamada de la hoja inferior, agregue las siguientes líneas.
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) {
}
});
Respuesta tardía, pero esto es lo que funcionó para mí, que es un poco diferente a lo que otros han sugerido.
Puede intentar establecer la propiedad
cancelable
en falso, es decir
setCancelable(false);
y luego manejando manualmente los eventos donde desea cerrar el diálogo en el método
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();
}
});
}
Esto funciona con un ListView dentro del fragmento de diálogo, que era donde me estaba quedando un poco atascado con otras soluciones.
Tengo el mismo problema en BottomSheetDialogFragment y aplico muchas soluciones usando el comportamiento del diálogo, pero ninguno de ellos resuelve mi problema y luego lo resolví, pero establecí
setCancelable(false);
en el momento de la inicialización del diálogo.
DialogEndRide dialogCompleteRide = new DialogEndRide();
dialogCompleteRide.setCancelable(false);
dialogCompleteRide.show(getChildFragmentManager(), "");
Esto deshabilitará el gesto en BottomSheetDialogFragment y puede descartar el diálogo mediante programación mediante el
dismiss();
función.
Terminé escribiendo una solución alternativa para abordar este caso de uso de deshabilitar dinámicamente el arrastre del usuario, mediante el cual BottomSheetBehavior se subclasifica para anular onInterceptTouchEvent e ignorarlo cuando un indicador personalizado (en este caso mAllowUserDragging) se establece en falso:
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);
}
}
Y en tu diseño 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" />
Hasta ahora, esta es la solución de comportamiento más consistente para deshabilitar el arrastre del usuario en la hoja inferior a pedido.
Todas las otras soluciones que se basaban en disparar otra llamada setState en la devolución de llamada onStateChanged dieron como resultado que BottomSheet se pusiera en mal estado o causara problemas de UX importantes (en el caso de publicar la llamada setState en un Runnable).
Espero que esto ayude a alguien :)
Rayo
compruebe el estado en el método
onStateChanged
de
setBottomSheetCallback
si el estado es
BottomSheetBehavior.STATE_DRAGGING
luego cámbielo a
BottomSheetBehavior.STATE_EXPANDED
esta manera puede detener
STATE_DRAGGING
por usuario.
como abajo
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) {
}
});
use el botón para abrir cerrar la hoja inferior como a continuación
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);
}
}
});
no use
setPeekHeight
o la
app:behavior_peekHeight
por encima puedes alcanzar tu objetivo
establezca bottomSheet onClickListener en nulo.
bottomSheet.setOnClickListener(null);
esta línea deshabilita todas las acciones sobre bottomSheet solamente y no afecta a la vista interna.
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();