Попробуйте понять поведение BottomSheet в библиотеке поддержки Android 23.2.1

Я пытаюсь реализовать Нижний лист в одном из своих действий, и я немного смущен тем, как он себя ведет!

Итак, вот проблема, у меня есть действие, в котором я пытаюсь показать нижний лист, и я вижу, что:

  1. если мы не установим свойство app:behavior_peekHeight, то нижний лист никогда не будет работать

  2. Если вы установите PeekHeight на что-то меньшее, чем 30dp (в основном просто чтобы скрыть его с экрана)

  3. Если вы установите для app:behavior_peekHeight значение более 30 dp в файле макета и попытаетесь установить состояние bottomSheetBehavior на STATE_HIDDEN в методе onCreate, ваше приложение вылетит с этой ошибкой.

вызванный:

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)

Я действительно смущен тем, почему он не позволяет мне скрыть его в onCreate? или почему мы не можем просто установить peekHeight в 0, чтобы он не был виден на экране, если мы не вызываем STATE_EXPANDED или даже не устанавливая это свойство, оно должно по умолчанию скрывать! или, по крайней мере, я должен иметь возможность установить его как скрытый в моем onCreate!

я что-то упускаю? или поведение BottomSheet жесткое?

мой файл макета для BottomSheet выглядит примерно так:

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

в своей деятельности я делаю что-то вроде этого:

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

В моем onclick я делаю это:

@Override
public void onItemClick(View view, int position) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}

person sujay    schedule 20.03.2016    source источник
comment
Вы выяснили причину первого случая: если мы не установим свойство app:behavior_peekHeight, то нижний лист никогда не будет работать? я попал в то же самое.   -  person Lạng Hoàng    schedule 24.03.2016
comment
@LạngHoàng этот ответ может помочь вам stackoverflow.com/a/36236743/3000299   -  person sujay    schedule 18.04.2016


Ответы (4)


Поработав над этой проблемой еще несколько дней, я нашел для этого одно альтернативное решение:

Вместо использования Bottom_sheet непосредственно внутри вашего макета, если мы создадим фрагмент Bottom_Sheet, а затем создадим его экземпляр в действии, эта проблема не возникнет, и нижний лист будет скрыт, и нам не нужно указывать peek_height.

вот что я сделал

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

Тогда в моей деятельности

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

Это фактически решило мою проблему с тем, что нижний лист не скрывается при запуске действия, но я до сих пор не могу понять, почему, если нижний_лист включен напрямую, мы сталкиваемся с этой проблемой!

person sujay    schedule 21.03.2016
comment
Это изменит ваш лист с постоянного нижнего листа на нижний лист модели. Несмотря на то, что это может показаться неважным, это может иметь огромное влияние. Постоянный нижний лист, например, позволяет взаимодействовать с содержимым над ним (пролистывать, печатать и т. д.). В то время как нижний лист модели не имеет. - person Entreco; 23.07.2016

(Ссылаясь на вопрос) Суззи, братан, проблема с вашим кодом в том, что вы пытаетесь вызвать метод setState непосредственно внутри onCreate. Это вызовет nullPointer, потому что WeakReference еще не инициализирован. Он будет инициализирован, когда макет Coordinator собирается создать дочернее представление.

onLayoutChild (родитель CoordinatorLayout, дочерний элемент V, int layoutDirection)

Вызывается, когда родительский объект CoordinatorLayout занимается макетом данного дочернего представления.

Таким образом, лучший подход — установить высоту просмотра на 0 и показать/скрыть внутри прослушивателя onItemClick. Вот мой код:

нижний_лист.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;
            }
        });

    }
    }

Здесь изначально нижний лист не виден. При нажатии кнопки мы установим состояние STATE_COLLAPSED/STATE_EXPANDED.

Учебное пособие, которому я следовал, чтобы создать это демонстрационное приложение, приведено ниже: %20Support%20Library%22" rel="nofollow">Нижний лист с библиотекой поддержки дизайна Android

person android_eng    schedule 26.03.2016
comment
да, я попробовал этот подход, но с этим подходом проблема заключалась в том, что мне нужно было установить свойство peek_height на нижнем листе больше 30. Я был немного сбит с толку, потому что, если я установил его на ноль, ничего не сработало! без ошибок и без нижнего листа я не мог понять почему так произошло! но из трех вещей ваш ответ помог мне понять причину одной из них, которая касалась слабой ссылки! Спасибо за ответ - person sujay; 27.03.2016

Причина его сбоя связана с тем, что слабая ссылка не устанавливается до одной из последних строк в onLayoutChild, что дает вам исключение null ptr.

Что вы можете сделать, так это создать собственное поведение BottomSheet и переопределить onLayoutChild, установив там расширенное состояние.

Пример можно найти здесь: NullPointerExeption с AppCompat BottomSheets

person 12vi6    schedule 20.03.2016
comment
предложение использовать пользовательское действие и наследовать его решает проблему, но почему weakReference не установлен на первом месте? это особенность дизайна, из-за которой важно не устанавливать weakReference до того, как дочерний макет не будет загружен полностью? - person sujay; 21.03.2016

Чтобы избежать исключения нулевого указателя, установите состояние HIDDEN, как это в 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);
            }
        });
person iam thadiyan    schedule 07.04.2016
comment
Это решение работает, но есть проблема, связанная с жизненным циклом Activity... например, если runnable выполняется после того, как Activity приостановлено. - person Ray W; 22.04.2016
comment
как я могу получить состояние, например, я хочу видеть, отображается ли полный вид или пользователям нужно прокручивать вверх. так что я могу показать кнопку дополнительной информации внизу, если присутствует больше данных, чем текущее представление - person andro; 17.04.2017
comment
как я могу получить состояние, например, я хочу видеть, отображается ли полный вид или пользователям нужно прокручивать вверх. так что я могу показать кнопку дополнительной информации внизу, если присутствует больше данных, чем текущее представление - person andro; 17.04.2017