Android support 23.2 BottomSheetBehaviorを使ったピット
4914 ワード
dim.red新しく出たdesign:23.0新しいBehaviorを導入しました:BottomSheetBehavior
に質問
設定BottomSheetBehaviorがPeekHeightまたはPeekHeightを0に設定していない場合.下部のBottomSheetBehaviorビューがスライドしません.
ぶんせき
ソースに入ることによって、具体的な問題は
最初のviewの位置はスクリーンの中です.mStateの初期状態がSTATE_なのでCOLLAPSED、mPeekHeightは0、mMaxOffsetはrvの高さになったので、viewはすぐにスクリーンから外された.そして後ろのViewは全行程透明になった.奇抜だ.
ソリューション
ソリューション1
強制再描画を開始します
欠点はrequestLayoutメソッドを使用することです.
ソリューション2
これはラッキーScienceが提供しています
クラス:
23以下に存在する可能性のあるバグであることがわかる.同時に、
最終案
シナリオ2に基づいてちょっとした修正をしてgoogleを使うシナリオです.
尻尾
Googleはこれを開発する際にこのような応用シーンを考慮していないはずだ.シーンがそうであれば
に質問
設定BottomSheetBehaviorがPeekHeightまたはPeekHeightを0に設定していない場合.下部のBottomSheetBehaviorビューがスライドしません.
ぶんせき
ソースに入ることによって、具体的な問題は
@Override
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
// First let the parent lay it out
if (mState != STATE_DRAGGING && mState != STATE_SETTLING) {
parent.onLayoutChild(child, layoutDirection);
}
// Offset the bottom sheet
mParentHeight = parent.getHeight();
mMinOffset = Math.max(0, mParentHeight - child.getHeight());
mMaxOffset = mParentHeight - mPeekHeight;
if (mState == STATE_EXPANDED) {
ViewCompat.offsetTopAndBottom(child, mMinOffset);
} else if (mHideable && mState == STATE_HIDDEN) {
ViewCompat.offsetTopAndBottom(child, mParentHeight);
} else if (mState == STATE_COLLAPSED) {
ViewCompat.offsetTopAndBottom(child, mMaxOffset);
}
if (mViewDragHelper == null) {
mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
}
mViewRef = new WeakReference<>(child);
mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
return true;
}
最初のviewの位置はスクリーンの中です.mStateの初期状態がSTATE_なのでCOLLAPSED、mPeekHeightは0、mMaxOffsetはrvの高さになったので、viewはすぐにスクリーンから外された.そして後ろのViewは全行程透明になった.奇抜だ.
ソリューション
ソリューション1
強制再描画を開始します
behavior.setBottomSheetCallback(new BottomSheet.BottomSheetCallback() {
public boolean hasRequest;
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
if (!hasRequest && behavior.getPeekHeight() == 0 && slideOffset > 0) {
hasRequest = true;
bottomSheet.requestLayout();
}
}
});
欠点はrequestLayoutメソッドを使用することです.
ソリューション2
これはラッキーScienceが提供しています
bottomSheet.setTranslationY(statusbarheight);
behavior.setBottomSheetCallback(new BottomSheet.BottomSheetCallback() {
public boolean hasRequest;
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
if (!hasRequest && behavior.getPeekHeight() == 0 && slideOffset > 0) {
hasRequest = true;
bottomSheet.setTranslationY(0);
}
}
});
TranslationY
の差分値を設定ことにより.彼に再描画させる.Google Designパッケージの下に似たような解決策があることをぼんやり覚えています.同じようにTranslationY
の差を使っています.クラス:
android.support.design.widget.ViewOffsetHelper
メソッド:updateOffsets
private void updateOffsets() {
ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
// Manually invalidate the view and parent to make sure we get drawn pre-M
if (Build.VERSION.SDK_INT < 23) {
tickleInvalidationFlag(mView);
final ViewParent vp = mView.getParent();
if (vp instanceof View) {
tickleInvalidationFlag((View) vp);
}
}
}
private static void tickleInvalidationFlag(View view) {
final float y = ViewCompat.getTranslationY(view);
ViewCompat.setTranslationY(view, y + 1);
ViewCompat.setTranslationY(view, y);
}
23以下に存在する可能性のあるバグであることがわかる.同時に、
ViewOffsetHelper
は私有のクラスであり、updateOffsets
は私有の方法であることに注意しなければならない.だからcopyしか使えないし、直接使うことはできません.最終案
シナリオ2に基づいてちょっとした修正をしてgoogleを使うシナリオです.
behavior.setBottomSheetCallback(new BottomSheet.BottomSheetCallback() {
public boolean hasRequest;
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
if (!hasRequest && behavior.getPeekHeight() == 0 && slideOffset > 0) {
hasRequest = true;
updateOffsets(bottomSheet);
}
}
});
private void updateOffsets(View view) {
// Manually invalidate the view and parent to make sure we get drawn pre-M
if (Build.VERSION.SDK_INT < 23) {
tickleInvalidationFlag(view)
final ViewParent vp = view.getParent();
if (vp instanceof View) {
tickleInvalidationFlag((View) vp);
}
}
}
private static void tickleInvalidationFlag(View view) {
final float y = ViewCompat.getTranslationY(view);
ViewCompat.setTranslationY(view, y + 1);
ViewCompat.setTranslationY(view, y);
}
尻尾
Googleはこれを開発する際にこのような応用シーンを考慮していないはずだ.シーンがそうであれば
BottomSheetDialog
という代替を用いることができる.