在實現BottomSheetDialog中嵌入Webview的時候,會向下拖動會將整個dialog消失掉而不是滑動webview內容,以下: web
通常webview的向下滑動/拖動的效果應該是能夠正常顯現出來的,而BottomSheetDialog控件自己自帶的拖動效果也是將其整個View給消失掉的,這樣二者在同時向下拖動時就會產生部分衝突。(若是沒有衝突,那麼一定是谷歌在設計時以及作了處理。)所以,能夠把問題的解決關鍵假定爲:當發生向下動做的,去解決這之間的「衝突」。bash
翻開BottomSheetDialog的源碼,發現內容並很少: ide
能夠看見,全部setContentView的入口都調用了這個wrapInBottomSheet方法。private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
final FrameLayout container = (FrameLayout) View.inflate(getContext(),
R.layout.design_bottom_sheet_dialog, null);
final CoordinatorLayout coordinator =
(CoordinatorLayout) container.findViewById(R.id.coordinator);
if (layoutResId != 0 && view == null) {
view = getLayoutInflater().inflate(layoutResId, coordinator, false);
}
FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
mBehavior = BottomSheetBehavior.from(bottomSheet);
mBehavior.setBottomSheetCallback(mBottomSheetCallback);
mBehavior.setHideable(mCancelable);
if (params == null) {
bottomSheet.addView(view);
} else {
bottomSheet.addView(view, params);
}
//...省略
return container;
}
複製代碼
傳入的View最終會被add進一個FrameLayout的bottomSheet中,而後經過bottomSheet來實例化一個BottomSheetBehavior,以後給這個mBehavior設置了一個mBottomSheetCallback,咱們來看看其內容是什麼:源碼分析
private BottomSheetBehavior.BottomSheetCallback mBottomSheetCallback
= new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet,
@BottomSheetBehavior.State int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
cancel();
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
};
複製代碼
能夠看出裏面涉及到了對BottomSheet的狀態監聽,邏輯判斷則是根據BottomSheetBehavior的狀態來進行相應處理,再來看看BottomSheetBehavior中有哪些狀態:ui
/**
* The bottom sheet is dragging.
*/
public static final int STATE_DRAGGING = 1;
/**
* The bottom sheet is settling.
*/
public static final int STATE_SETTLING = 2;
/**
* The bottom sheet is expanded.
*/
public static final int STATE_EXPANDED = 3;
/**
* The bottom sheet is collapsed.
*/
public static final int STATE_COLLAPSED = 4;
/**
* The bottom sheet is hidden.
*/
public static final int STATE_HIDDEN = 5;
複製代碼
找到了STATE_DRAGGING 狀態,假定咱們能在BottomSheetCallback的onStateChanged的監聽方法中能監聽到該對應的動做,那麼咱們就能攔截處理一開始出現的問題。 因而,在onStateChanged中輸出日誌,打印各動做的newState對應的狀態碼是多少,最後發現,果真當向下拖動整個view時,其newState爲STATE_DRAGGING。所以,只要在這裏將狀態改成不是該狀態可能就會實現要求的效果。根據名稱選擇STATE_EXPANDED 來作相應的處理。idea
可是如何來作呢? BottomSheetCallback是經過BottomSheetBehavior來set的,而BottomSheetBehavior則有spa
public static <V extends View> BottomSheetBehavior<V> from(V view)
複製代碼
的靜態方法來實例化,因而到這裏就很清晰了。設計
private BottomSheetBehavior.BottomSheetCallback mBottomSheetCallback
= new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet,
@BottomSheetBehavior.State int newState) {
if (newState == BottomSheetBehavior.STATE_DRAGGING) {//判斷爲向下拖動行爲時,則強制設定狀態爲展開
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED );
}
LogUtil.e(TAG, "onStateChanged——>" + newState);
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
LogUtil.e(TAG, "onSlide——>" + slideOffset);
}
};
複製代碼
mBottomSheetDialog.setmBottomSheetCallback((FrameLayout)(view.getParent()));//由於view是被add進去,設置的回調監聽是其parent view
複製代碼
public void setmBottomSheetCallback(View sheetView) {
if (bottomSheetBehavior == null) {
bottomSheetBehavior = BottomSheetBehavior.from(sheetView);
}
bottomSheetBehavior.setBottomSheetCallback(mBottomSheetCallback);
}
複製代碼
以上只是簡單地結合源碼分析並提出猜測的一種可解決方案,還有不少問題並未深究。一開始所說的「衝突」實際上是已經被谷歌解決了的,只是在依據此的基礎上作了些額外的處理使其能依照其規則正常的運行。其它例如加入RecycleView等也應該是相似的解決方案,一步步分析源碼和猜測嘗試,總會解決。3d