Try to Understand the behavior of BottomSheet in android support library 23.2.1

12,824

Solution 1

After working on this issue for few more days I found one alternate solution for this:

Instead of using the Bottom_sheet directly inside your layout, if we create a Bottom_Sheet fragment and then instantiate it in the activity this issue will not occur and the bottom sheet will be hidden and we dont need to specify the peek_height

here is what I did

public class BottomSheetDialog extends BottomSheetDialogFragment implements View.OnClickListener {
    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container, 
                             Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_bottom_sheet, container, false);
}

Then in my activity

bottomSheetDialog = BottomSheetDialog.newInstance(addressList.get(position), position);
bottomSheetDialog.show(getSupportFragmentManager(), AddressActivity.class.getSimpleName());

This actually solved my problem of bottom sheet being not hidden when the activity starts but I am still not able to understand why if bottom_sheet is included directly we face that problem!

Solution 2

(Referring to the question) Suzzi bro the issue with your code is you are trying to call the setState method directly inside onCreate. This is will throw a nullPointer because the WeakReference is not initialized yet. It will get initialized when the Coordinator layout is about to lay its child view.

onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection)

Called when the parent CoordinatorLayout is about the lay out the given child view.

So the best approach is set the peek height to 0 and show/hide inside the onItemClick listener. Here is my code:

bottom_sheet.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Bottom sheet"
        android:textColor="@android:color/black" />

</LinearLayout>

activity_main.xml

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Show hide bottom sheet" />


<include
    android:id="@+id/gmail_bottom_sheet"
    layout="@layout/bottom_sheet" />

MainActivity.java

 public class MainActivity extends AppCompatActivity {
        boolean isExpanded;
        Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CoordinatorLayout coordinatorLayout = (CoordinatorLayout) findViewById(R.id.gmail_coordinator);
        final View bottomSheet = coordinatorLayout.findViewById(R.id.gmail_bottom_sheet);
        final BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isExpanded) {
                    behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                } else {
                    behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                }
                isExpanded = !isExpanded;
            }
        });

    }
    }

Here initially the bottom sheet is not visible. On clicking the button we will be set the state to STATE_COLLAPSED/STATE_EXPANDED.

The tutorial I followed to make this demo app is listed below: Bottom Sheet with Android Design Support Library

Solution 3

To avoid the Null pointer exception, set the state to HIDDEN like this in onCreate()

View bottomSheetView = findViewById(R.id.bottomsheet_review_detail_id);
mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheetView);
bottomSheetView.post(new Runnable() {
            @Override
            public void run() {
                mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
            }
        });

Solution 4

The reason its crashing is due to the fact that the weak reference is not being set until one of the last lines in onLayoutChild, which gives you your null ptr exception.

What you can do is create a custom BottomSheet Behavior and override onLayoutChild, setting the expanded state there.

An example can be found here: NullPointerExeption with AppCompat BottomSheets

Share:
12,824
sujay
Author by

sujay

Updated on July 25, 2022

Comments

  • sujay
    sujay almost 2 years

    I am trying to implement Bottom sheet in one of my activities and I am kind of confused by the way it is behaving!

    So here is the problem, I have an activity in which I am trying to show Bottom sheet and I see that:

    1. if we dont set the app:behavior_peekHeight property then the Bottom sheet never works

    2. If you set the PeekHeight to something less than 30dp (basically just to hide it from screen)

    3. If you set app:behavior_peekHeight to more than 30dp in layout file and try to set the state of bottomSheetBehavior to STATE_HIDDEN in you onCreate method your app crashes with this error

    caused by:

    java.lang.NullPointerException: Attempt to invoke virtual method
    'java.lang.Object java.lang.ref.WeakReference.get()' on a null object reference             at    android.support.design.widget.BottomSheetBehavior.setState(BottomSheetBehavior.jav    a:440)
    at myapp.activity.SomeActivity.onCreate(SomeActivity.java:75)
    

    I am really confused on why is it not allowing me to hide it in onCreate? or why cant we just set the peekHeight to 0 so that it is not visible on screen unless we call the STATE_EXPANDED or even not setting that property should default it to hide! or atleast I should be able to set it as hidden in my onCreate!

    am I missing something? or is the behavior of the BottomSheet rigid?

    my layout file for the BottomSheet is something like this:

    <LinearLayout 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:background="@android:color/white"
    android:layout_height="100dp"
    android:orientation="vertical"
    app:behavior_hideable="true"
    app:behavior_peekHeight="40dp" <!-- I cant set this less than 30dp just to hide-->
    app:layout_behavior="@string/bottom_sheet_behavior"
    tools:context="someActivity"
    android:id="@+id/addressbottomSheet"
    tools:showIn="@layout/some_activity">
    

    in my activity I am doing something like this:

    @InjectView(R.id.addressbottomSheet)
     View bottomSheetView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    ....
    bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetView);
    
    // only if I have set peek_height to more than 30dp
    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); 
    }
    

    In my onclick I am doing this:

    @Override
    public void onItemClick(View view, int position) {
    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }
    
  • sujay
    sujay about 8 years
    suggestion to use a custom activity and inherit it solves the issue but why is the weakReference not set at first place? is it a design thing that makes it important to not to set weakReference before the child layout is not loaded completely?
  • sujay
    sujay about 8 years
    yup I tried this approach but with this approach the problem I had was I had to set the peek_height property in bottom sheet to be more than 30 I was kind of confused because if I set it to zero nothing worked! no errors and no bottom sheet I could not figure out why that happened! but out of three things your answer helped me figure out the reason for one of them which was regarding the "weakReference"! thanks for the answer
  • Ray W
    Ray W about 8 years
    This solution works, but there's a problem when it comes to the Activity's lifecycle... such as if the runnable executes after the activity is paused.
  • Entreco
    Entreco almost 8 years
    Doing this will change your sheet from a persistent bottomsheet to a model bottomsheet. Alltough this might seem unimportant, it can have a huge impact. Persistent bottomsheet, for example allows to interact with the content above it (swiping, typing, etc). Whereas a model bottom sheet does not.
  • andro
    andro about 7 years
    how i can get state , like i want to see is full view displayed or users need to scroll up . so that i can show more info button in bottom if more data is present then current view
  • andro
    andro about 7 years
    how i can get state , like i want to see is full view displayed or users need to scroll up . so that i can show more info button in bottom if more data is present then current view