如何为Android(Java)Bottom Sheet Dialog添加OvershootInterpolator且无空白间隙
实现Bottom Sheet显示/隐藏时的过冲动画(无窗口偏移)
针对你遇到的窗口偏移、内容裁剪问题,有两种可行方案实现无窗口偏移的过冲动画:
方案一:自定义BottomSheetBehavior(推荐)
通过重写BottomSheetBehavior的动画逻辑,直接替换状态切换时的插值器,同时确保动画作用于内容View而非窗口,避免底部留白。
步骤1:自定义Behavior类
public class OvershootBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> { // 调整参数可以改变过冲幅度,1.0f为默认强度 private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator(1.0f); public OvershootBottomSheetBehavior() { super(); } public OvershootBottomSheetBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override void animateToState(int state, int interpolator, int duration) { // 替换默认插值器为Overshoot super.animateToState( state, interpolator == -1 ? OVERSHOOT_INTERPOLATOR : ContextCompat.getInterpolator(getContext(), interpolator), duration ); } }
步骤2:更新布局文件
将原布局中的Behavior替换为自定义类:
<!-- bottom_sheet_dialog.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/rootLinearLayout" android:layout_width="match_parent" android:layout_height="200dp" android:orientation="vertical" android:background="@color/#487948" app:layout_behavior="com.yourpackage.OvershootBottomSheetBehavior"> </LinearLayout>
步骤3:配置BottomSheetDialog
关闭窗口动画,允许内容超出边界避免裁剪:
BottomSheetDialog sheetDialog = new BottomSheetDialog(this, R.style.TransparentBackgroundStyle); sheetDialog.setContentView(R.layout.bottom_sheet_dialog); // 关闭窗口自带动画,避免冲突 Objects.requireNonNull(sheetDialog.getWindow()).setWindowAnimations(0); // 允许内容超出窗口边界,防止过冲时顶部被裁剪 sheetDialog.getWindow().setFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ); BottomSheetBehavior<LinearLayout> behavior = BottomSheetBehavior.from(sheetDialog.findViewById(R.id.rootLinearLayout)); behavior.setState(BottomSheetBehavior.STATE_EXPANDED); sheetDialog.show();
方案二:监听状态手动添加View动画
如果不想自定义Behavior,可以通过监听BottomSheet的状态变化,手动给内容View添加平移动画模拟过冲效果。
实现代码
BottomSheetDialog sheetDialog = new BottomSheetDialog(this, R.style.TransparentBackgroundStyle); sheetDialog.setContentView(R.layout.bottom_sheet_dialog); // 关闭窗口自带动画 Objects.requireNonNull(sheetDialog.getWindow()).setWindowAnimations(0); // 允许内容超出窗口边界 sheetDialog.getWindow().setFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ); LinearLayout bottomSheetView = sheetDialog.findViewById(R.id.rootLinearLayout); BottomSheetBehavior<LinearLayout> behavior = BottomSheetBehavior.from(bottomSheetView); // 监听状态变化,添加过冲动画 behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_SETTLING) { if (behavior.getState() == BottomSheetBehavior.STATE_EXPANDED) { // 显示时:先向下偏移再回到原位 ObjectAnimator showAnim = ObjectAnimator.ofFloat(bottomSheet, "translationY", 50f, 0f); showAnim.setInterpolator(new OvershootInterpolator(1.2f)); showAnim.setDuration(500); showAnim.start(); } else if (behavior.getState() == BottomSheetBehavior.STATE_HIDDEN) { // 隐藏时:先向上偏移再滑出屏幕 ObjectAnimator hideAnim = ObjectAnimator.ofFloat(bottomSheet, "translationY", -50f, bottomSheet.getHeight()); hideAnim.setInterpolator(new OvershootInterpolator(1.2f)); hideAnim.setDuration(500); hideAnim.start(); } } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { // 滑动交互时的动画可在此处理,按需添加 } }); behavior.setState(BottomSheetBehavior.STATE_EXPANDED); sheetDialog.show();
关键注意事项
- 必须设置
FLAG_LAYOUT_NO_LIMITS,否则过冲时超出窗口的内容会被裁剪 - 关闭窗口自带动画(
setWindowAnimations(0)),避免和自定义动画冲突 - 调整
OvershootInterpolator的构造参数可以改变过冲的幅度,数值越大过冲越明显
内容的提问来源于stack exchange,提问作者user22635266
相关产品推荐
相关产品推荐

