尝试了解 android 支持库 23.2.1 中 BottomSheet 的行为
Try to Understand the behavior of BottomSheet in android support library 23.2.1
我正在尝试在我的一项活动中实施底部 sheet,我对它的行为方式有点困惑!
所以这就是问题所在,我有一个 activity,我试图在其中显示 Bottom sheet,我看到了:
如果我们不设置 app:behavior_peekHeight
属性 那么底部 sheet 永远不会起作用
如果您将 PeekHeight 设置为小于 30dp(基本上只是为了从屏幕上隐藏它)
- 如果您在布局文件中将
app:behavior_peekHeight
设置为超过 30dp 并尝试在您的 onCreate 方法中将 bottomSheetBehavior
的状态设置为 STATE_HIDDEN
您的应用程序会因此错误而崩溃
原因:
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">
在我的 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);
}
它崩溃的原因是弱引用直到 onLayoutChild 的最后一行之一才被设置,这给了你 null ptr 异常。
您可以做的是创建自定义 BottomSheet Behavior 并覆盖 onLayoutChild,在那里设置展开状态。
可在此处找到示例:
在处理这个问题几天后,我找到了一个替代解决方案:
如果我们创建一个 Bottom_Sheet 片段,然后在 activity 中实例化它,而不是直接在您的布局中使用 Bottom_sheet,则不会发生此问题并且底部 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);
}
然后在我的activity
bottomSheetDialog = BottomSheetDialog.newInstance(addressList.get(position), position);
bottomSheetDialog.show(getSupportFragmentManager(), AddressActivity.class.getSimpleName());
这实际上解决了我在 activity 启动时未隐藏底部 sheet 的问题,但我仍然无法理解为什么如果直接包含 bottom_sheet 我们会面临该问题!
(指的是问题)Suzzi 兄弟,您的代码存在问题,您正试图在 onCreate 中直接调用 setState 方法。这将抛出一个 nullPointer,因为 WeakReference 尚未初始化。当 Coordinator 布局即将放置其子视图时,它将被初始化。
onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection)
Called when the parent CoordinatorLayout is about the lay out the
given child view.
所以最好的方法是在 onItemClick 侦听器中将窥视高度设置为 0 和 show/hide。
这是我的代码:
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;
}
});
}
}
这里最初底部 sheet 是不可见的。单击按钮时,我们会将状态设置为 STATE_COLLAPSED/STATE_EXPANDED。
下面列出了我制作此演示应用程序所遵循的教程:
Bottom Sheet with Android Design Support Library
为了避免空指针异常,在onCreate()中像这样设置状态为HIDDEN
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);
}
});
我正在尝试在我的一项活动中实施底部 sheet,我对它的行为方式有点困惑!
所以这就是问题所在,我有一个 activity,我试图在其中显示 Bottom sheet,我看到了:
如果我们不设置
app:behavior_peekHeight
属性 那么底部 sheet 永远不会起作用如果您将 PeekHeight 设置为小于 30dp(基本上只是为了从屏幕上隐藏它)
- 如果您在布局文件中将
app:behavior_peekHeight
设置为超过 30dp 并尝试在您的 onCreate 方法中将bottomSheetBehavior
的状态设置为STATE_HIDDEN
您的应用程序会因此错误而崩溃
原因:
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">
在我的 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);
}
它崩溃的原因是弱引用直到 onLayoutChild 的最后一行之一才被设置,这给了你 null ptr 异常。
您可以做的是创建自定义 BottomSheet Behavior 并覆盖 onLayoutChild,在那里设置展开状态。
可在此处找到示例:
在处理这个问题几天后,我找到了一个替代解决方案:
如果我们创建一个 Bottom_Sheet 片段,然后在 activity 中实例化它,而不是直接在您的布局中使用 Bottom_sheet,则不会发生此问题并且底部 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);
}
然后在我的activity
bottomSheetDialog = BottomSheetDialog.newInstance(addressList.get(position), position);
bottomSheetDialog.show(getSupportFragmentManager(), AddressActivity.class.getSimpleName());
这实际上解决了我在 activity 启动时未隐藏底部 sheet 的问题,但我仍然无法理解为什么如果直接包含 bottom_sheet 我们会面临该问题!
(指的是问题)Suzzi 兄弟,您的代码存在问题,您正试图在 onCreate 中直接调用 setState 方法。这将抛出一个 nullPointer,因为 WeakReference 尚未初始化。当 Coordinator 布局即将放置其子视图时,它将被初始化。
onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection)
Called when the parent CoordinatorLayout is about the lay out the given child view.
所以最好的方法是在 onItemClick 侦听器中将窥视高度设置为 0 和 show/hide。 这是我的代码:
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;
}
});
}
}
这里最初底部 sheet 是不可见的。单击按钮时,我们会将状态设置为 STATE_COLLAPSED/STATE_EXPANDED。
下面列出了我制作此演示应用程序所遵循的教程: Bottom Sheet with Android Design Support Library
为了避免空指针异常,在onCreate()中像这样设置状态为HIDDEN
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);
}
});