项目开发中使用了谷歌推荐的实现类似网易云音乐的上弹对话框BottomSheetDialog控件,该控件在竖屏状态下显示没有问题,但是在横屏状态下弹窗只能显示一半,需要手动往上滑一下才能完全显示。在网上找了下解决方案,看到了https://www.jianshu.com/p/50c54d8e0d4a 相同的问题,但是这篇文章中只给了相应的解决方案,没有完整的代码,对于使用原生的BottomSheetDialog人员来说,根本就是个鸡肋。这里我结合源码和上述文章中的解决方案,整理成一个完整的自定义BottomSheetDialog供后来者使用,希望能帮助你们。
特别注意:这里对应的布局文件和id对应的R文件直接引用你们项目中的R文件就可以,布局使用的是Android 自带的布局文件,只要使用Android studio进入BottomDialog的源码,点击下面图片中的位置即可使
用。
下面是完整代码:
1 import android.content.Context; 2 import android.content.res.TypedArray; 3 import android.os.Build; 4 import android.os.Bundle; 5 import android.support.annotation.LayoutRes; 6 import android.support.annotation.NonNull; 7 import android.support.annotation.StyleRes; 8 import android.support.design.widget.BottomSheetBehavior; 9 import android.support.design.widget.CoordinatorLayout; 10 import android.support.v4.view.AccessibilityDelegateCompat; 11 import android.support.v4.view.ViewCompat; 12 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 13 import android.support.v7.app.AppCompatDialog; 14 import android.util.TypedValue; 15 import android.view.MotionEvent; 16 import android.view.View; 17 import android.view.ViewGroup; 18 import android.view.Window; 19 import android.widget.FrameLayout; 20 21 22 public class BaseBottomSheetDialog extends AppCompatDialog { 23 private BottomSheetBehavior<FrameLayout> behavior; 24 boolean cancelable; 25 private boolean canceledOnTouchOutside; 26 private boolean canceledOnTouchOutsideSet; 27 private BottomSheetBehavior.BottomSheetCallback bottomSheetCallback; 28 29 public BaseBottomSheetDialog(@NonNull Context context) { 30 this(context, 0); 31 } 32 33 public BaseBottomSheetDialog(@NonNull Context context, @StyleRes int theme) { 34 super(context, getThemeResId(context, theme)); 35 this.cancelable = true; 36 this.canceledOnTouchOutside = true; 37 this.bottomSheetCallback = new NamelessClass_1(); 38 this.supportRequestWindowFeature(1); 39 } 40 41 protected BaseBottomSheetDialog(@NonNull Context context, boolean cancelable, OnCancelListener cancelListener) { 42 super(context, cancelable, cancelListener); 43 this.cancelable = true; 44 this.canceledOnTouchOutside = true; 45 46 47 48 this.bottomSheetCallback = new NamelessClass_1(); 49 this.supportRequestWindowFeature(1); 50 this.cancelable = cancelable; 51 } 52 53 public void setContentView(@LayoutRes int layoutResId) { 54 super.setContentView(this.wrapInBottomSheet(layoutResId, (View)null, (ViewGroup.LayoutParams)null)); 55 } 56 class NamelessClass_1 extends BottomSheetBehavior.BottomSheetCallback { 57 NamelessClass_1() { 58 } 59 60 public void onStateChanged(@NonNull View bottomSheet, int newState) { 61 if (newState == 5) { 62 BaseBottomSheetDialog.this.cancel(); 63 } 64 65 } 66 67 public void onSlide(@NonNull View bottomSheet, float slideOffset) { 68 } 69 } 70 protected void onCreate(Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 Window window = this.getWindow(); 73 if (window != null) { 74 if (Build.VERSION.SDK_INT >= 21) { 75 window.clearFlags(67108864); 76 window.addFlags(-2147483648); 77 } 78 79 window.setLayout(-1, -1); 80 } 81 82 } 83 84 public void setContentView(View view) { 85 super.setContentView(this.wrapInBottomSheet(0, view, (ViewGroup.LayoutParams)null)); 86 } 87 88 public void setContentView(View view, ViewGroup.LayoutParams params) { 89 super.setContentView(this.wrapInBottomSheet(0, view, params)); 90 } 91 92 public void setCancelable(boolean cancelable) { 93 super.setCancelable(cancelable); 94 if (this.cancelable != cancelable) { 95 this.cancelable = cancelable; 96 if (this.behavior != null) { 97 this.behavior.setHideable(cancelable); 98 } 99 } 100 101 } 102 103 protected void onStart() { 104 super.onStart(); 105 if (this.behavior != null) { 106 this.behavior.setState(3); 107 } 108 } 109 110 public void setCanceledOnTouchOutside(boolean cancel) { 111 super.setCanceledOnTouchOutside(cancel); 112 if (cancel && !this.cancelable) { 113 this.cancelable = true; 114 } 115 116 this.canceledOnTouchOutside = cancel; 117 this.canceledOnTouchOutsideSet = true; 118 } 119 120 private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) { 121 FrameLayout container = (FrameLayout)View.inflate(this.getContext(), R.layout.design_bottom_sheet_dialog, (ViewGroup)null); 122 CoordinatorLayout coordinator = (CoordinatorLayout)container.findViewById(R.id.coordinator); 123 if (layoutResId != 0 && view == null) { 124 view = this.getLayoutInflater().inflate(layoutResId, coordinator, false); 125 } 126 127 FrameLayout bottomSheet = (FrameLayout)coordinator.findViewById(R.id.design_bottom_sheet); 128 this.behavior = BottomSheetBehavior.from(bottomSheet); 129 this.behavior.setBottomSheetCallback(this.bottomSheetCallback); 130 this.behavior.setHideable(this.cancelable); 131 if (params == null) { 132 bottomSheet.addView(view); 133 } else { 134 bottomSheet.addView(view, params); 135 } 136 coordinator.findViewById(R.id.touch_outside).setOnClickListener(new View.OnClickListener() { 137 @Override 138 public void onClick(View v) { 139 if (BaseBottomSheetDialog.this.cancelable && BaseBottomSheetDialog.this.isShowing() && BaseBottomSheetDialog.this.shouldWindowCloseOnTouchOutside()) { 140 BaseBottomSheetDialog.this.cancel(); 141 } 142 } 143 }); 144 ViewCompat.setAccessibilityDelegate(bottomSheet, new AccessibilityDelegateCompat() { 145 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { 146 super.onInitializeAccessibilityNodeInfo(host, info); 147 if (BaseBottomSheetDialog.this.cancelable) { 148 info.addAction(1048576); 149 info.setDismissable(true); 150 } else { 151 info.setDismissable(false); 152 } 153 154 } 155 156 public boolean performAccessibilityAction(View host, int action, Bundle args) { 157 if (action == 1048576 &&BaseBottomSheetDialog.this.cancelable) { 158 BaseBottomSheetDialog.this.cancel(); 159 return true; 160 } else { 161 return super.performAccessibilityAction(host, action, args); 162 } 163 } 164 }); 165 bottomSheet.setOnTouchListener((view1, event) -> true); 166 return container; 167 } 168 169 boolean shouldWindowCloseOnTouchOutside() { 170 if (!this.canceledOnTouchOutsideSet) { 171 TypedArray a = this.getContext().obtainStyledAttributes(new int[]{16843611}); 172 this.canceledOnTouchOutside = a.getBoolean(0, true); 173 a.recycle(); 174 this.canceledOnTouchOutsideSet = true; 175 } 176 177 return this.canceledOnTouchOutside; 178 } 179 180 private static int getThemeResId(Context context, int themeId) { 181 if (themeId == 0) { 182 TypedValue outValue = new TypedValue(); 183 if (context.getTheme().resolveAttribute(R.attr.bottomSheetDialogTheme, outValue, true)) { 184 themeId = outValue.resourceId; 185 } else { 186 themeId = R.style.Theme_Design_Light_BottomSheetDialog; 187 } 188 } 189 190 return themeId; 191 } 192 }