web-dev-qa-db-fra.com

android BottomSheet comment réduire quand on clique à l'extérieur?

J'ai implémenté le comportement de feuille de fond avec NestedScrollView. Et je me demandais s'il était possible de masquer la vue de dessous lorsque touché en dehors.

22

Finalement j'ai pu faire ça,

Utilisé les lignes de code suivantes: 

@Override public boolean dispatchTouchEvent(MotionEvent event){
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (mBottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED) {

            Rect outRect = new Rect();
            bottomSheet.getGlobalVisibleRect(outRect);

            if(!outRect.contains((int)event.getRawX(), (int)event.getRawY()))
                mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    }

    return super.dispatchTouchEvent(event);
}
31

Merci l'OP pour la question/réponse. J'ai utilisé son code mais amélioré sa propreté et je voulais partager. Au lieu d'étendre une vue et d'ajouter l'interface, vous pouvez le coder directement dans BottomSheetBehavior. Comme ça:

AutoCloseBottomSheetBehavior.Java

import Android.content.Context;
import Android.graphics.Rect;
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 AutoCloseBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

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

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN &&
            getState() == BottomSheetBehavior.STATE_EXPANDED) {

            Rect outRect = new Rect();
            child.getGlobalVisibleRect(outRect);

            if (!outRect.contains((int) event.getRawX(), (int) event.getRawY())) {
                setState(BottomSheetBehavior.STATE_COLLAPSED);
            }
        }
        return super.onInterceptTouchEvent(parent, child, event);
    }
}

et ensuite vous l'ajoutez simplement à votre mise en page 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"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

   ... your normal content here ...
   <SomeLayout... />

    ... the bottom sheet with the behavior
    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical"
        app:layout_behavior="<com.package.name.of.the.class>.AutoCloseBottomSheetBehavior">

        ... the bottom sheet views

    </LinearLayout>

</Android.support.design.widget.CoordinatorLayout>
6
Budius

Pour l'activité:

@Override 
public boolean dispatchTouchEvent(MotionEvent event){
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (mBottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED) {

            Rect outRect = new Rect();
            bottomSheet.getGlobalVisibleRect(outRect);

            if(!outRect.contains((int)event.getRawX(), (int)event.getRawY()))
                mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    }

    return super.dispatchTouchEvent(event);
}

Pour le fragment: Utilisez la même méthode dans Activity like,

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (fragment != null && fragment instanceof HomeFragment) {
            ((HomeFragment) fragment).hideBottomSheetFromOutSide(event);
        }
    }
    return super.dispatchTouchEvent(event);
}

et créez la méthode dans le fragment comme:

   /**
     * Calling from Dashboard Activity
     *
     * @param event Motion Event
     */
    public void hideBottomSheetFromOutSide(MotionEvent event) {
        if (isBottomSheetMenuExpanded()) {
            Rect outRect = new Rect();
            mBinding.homeBottomSheetLayout.getGlobalVisibleRect(outRect);
            if (!outRect.contains((int) event.getRawX(), (int) event.getRawY()))
                mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    }

J'espère que ça vous aidera. 

Je vous remercie.

3
Pratik Butani

Définissez un auditeur de clic pour votre mise en page principale (la mise en page des coordonnées dans ce cas)

@OnClick(R.id.coordinateLayout)
public void onClickView(View view) {
    if (sheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
        sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
    }
}

Remarque: Butterknife est utilisé pour cliquer, sinon utilisez le code ci-dessous dans onCreate de l'activité.

CoordinateLayout layout = (CoordinateLayout) findViewById(R.id. coordinateLayout);
layout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (sheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
            sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    }
});
1
Abiranjan
someViewToClickOn.setOnClickListener(v -> 
    behavior.setState(BottomSheetBehavior.STATE_HIDDEN));

Cela fonctionne aussi! J'ai d'abord utilisé BottomSheetBehavior.STATE_COLLAPSED qui ne fonctionne pas

0
Boy

De nombreuses personnes ont trouvé un moyen d'implémenter dispatchTouchEvent sur fragment. Alors, voici comment ils peuvent le faire:

créer une mise en page personnalisée comme défini: 

public class DispatchTouchEvent extends LinearLayout {

    public interface onDispatchEvent
    {
        void dispatchEvent(MotionEvent e);
    }

    private onDispatchEvent dispatchEvent;

    public DispatchTouchEvent(Context context) {
        super(context);
    }

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

    public DispatchTouchEvent(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setDispatchEvent(onDispatchEvent dispatchEvent)
    {
        this.dispatchEvent=dispatchEvent;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(dispatchEvent!=null)
        {
            dispatchEvent.dispatchEvent(ev);
        }
        return super.dispatchTouchEvent(ev);
    }

}

Maintenant, utilisez cette mise en page comme base de votre mise en page de fragment. Inside fragment initialise cette présentation comme suit:

public class ABC extends fragment implements DispatchTouchEvent.onDispatchEvent
{

DispatchTouchEvent dispatchTouchEvent;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
....
    dispatchTouchEvent = (DispatchTouchEvent)rootView.findViewById(R.id.dispatch_event);
    dispatchTouchEvent.setDispatchEvent(this);
....
}

@Override
public void dispatchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
    if (mBottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED) 
    {

        Rect outRect = new Rect();
        bottomSheet.getGlobalVisibleRect(outRect);

        if(!outRect.contains((int)event.getRawX(), (int)event.getRawY()))   
         mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
    }
    }

    }

}
0