4

我一直在我的應用程序中使用AndroidSlidingUpPanel庫。從23.1.1版本開始,Android設計支持庫的版本就會在我的佈局中破壞一些東西。由於最新版本引入了BottomSheetBehavior,我正在尋找替代AndroidSlidingUpPanel庫並使用BottomSheetBehavior。然而,BottomSheetBehavior只有3個狀態,隱藏,摺疊和展開(以及2箇中間狀態拖拽和沉降)。 AndroidSlidingUpPanel還具有錨定狀態,這是面板在摺疊和展開之間捕捉的狀態。我怎麼能使用BottomSheetBehavior並獲得這個額外的錨定狀態?Android支持BottomSheetBehavior附加錨定狀態

Google的地圖應用程序具有此行爲。

隱藏:

已摺疊:

拖動(之間摺疊和錨定):

錨:

拖動(錨之間和膨脹):

擴展:

有與在固定狀態可選的圖像向上滑動在地圖上的位置時,讓他們去一些視差效果。當完全展開時,位置名稱將成爲操作欄標題。我最終還有興趣實現類似的目標。

我的第一個直覺是錨定狀態實際上是展開狀態,面板上方有空的空間,地圖仍然可見,是視圖的透明部分。然後,在錨定狀態和展開狀態之間拖動只是滾動面板視圖本身的內容。

這是通過以下事實驗證的:處於錨定狀態時,您可以通過在面板上方滑動可見地圖區域來繼續滾動面板。視圖的這個看不見的部分必須在從摺疊狀態向上滑動時向其區域展開(因爲可選圖像明顯),因爲無法從摺疊狀態的地圖上滑動面板。我想我可以走這條路,但想看看有沒有更好的方法。

+0

你有沒有發現與視差效果向上滑動過的圖像解決方案地圖? – MiguelHincapieC

+0

@MiguelHincapieC不,我沒有。就像我目前所看到的那樣,我只是將它滑到展開狀態,在屏幕上部分向上移動,就像上面的錨定位置一樣。仍然致力於完成視圖,以將更多內容擴展到全屏,並將視差效果合併到操作欄中。 –

+0

我猜想視差效果會在圖片滑動時使用'app:layout_collapseParallaxMultiplier',並且值爲 – MiguelHincapieC

回答

7

大更新 因爲有像4或大致相同的主題,但與型動物requeriments 5的問題,我試圖回答所有這些非禮貌管理員刪除/關閉它們讓我創建爲每一個票,改變它們以避免「複製粘貼」我會讓你鏈接到full answer,在那裏你可以找到關於如何獲得像谷歌地圖的完整行爲的所有解釋。


回答你的問題

我怎麼能使用BottomSheetBehavior並得到這種額外的固定狀態?

你可以這樣做修改默認BottomSheetBehavior增加一個統計有以下步驟:

  1. 創建一個Java類,並從CoordinatorLayout.Behavior<V>
  2. 複製粘貼代碼從默認BottomSheetBehavior文件擴展到您的新的一個。
  3. 修改方法clampViewPositionVertical用下面的代碼:

    @覆蓋 公衆詮釋clampViewPositionVertical(查看孩子,詮釋頂部,詮釋DY){ 回報約束(頂部,mMinOffset,mHideable mParentHeight:mMaxOffset); } int constrain(int amount,int low,int high){ return amount < low?低:(金額>高?高:金額); }

  4. 添加一個新的狀態

    公共靜態最終詮釋STATE_ANCHOR_POINT = X;

  5. 修改下一個方法:onLayoutChildonStopNestedScrollBottomSheetBehavior<V> from(V view)setState(可選)



我要添加這些改進方法和link to the example project

public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { 
    // First let the parent lay it out 
    if (mState != STATE_DRAGGING && mState != STATE_SETTLING) { 
     if (ViewCompat.getFitsSystemWindows(parent) && 
       !ViewCompat.getFitsSystemWindows(child)) { 
      ViewCompat.setFitsSystemWindows(child, true); 
     } 
     parent.onLayoutChild(child, layoutDirection); 
    } 
    // Offset the bottom sheet 
    mParentHeight = parent.getHeight(); 
    mMinOffset = Math.max(0, mParentHeight - child.getHeight()); 
    mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset); 

    //if (mState == STATE_EXPANDED) { 
    // ViewCompat.offsetTopAndBottom(child, mMinOffset); 
    //} else if (mHideable && mState == STATE_HIDDEN... 
    if (mState == STATE_ANCHOR_POINT) { 
     ViewCompat.offsetTopAndBottom(child, mAnchorPoint); 
    } else 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; 
} 


public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { 
    if (child.getTop() == mMinOffset) { 
     setStateInternal(STATE_EXPANDED); 
     return; 
    } 
    if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) { 
     return; 
    } 
    int top; 
    int targetState; 
    if (mLastNestedScrollDy > 0) { 
     //top = mMinOffset; 
     //targetState = STATE_EXPANDED; 
     int currentTop = child.getTop(); 
     if (currentTop > mAnchorPoint) { 
      top = mAnchorPoint; 
      targetState = STATE_ANCHOR_POINT; 
     } 
     else { 
      top = mMinOffset; 
      targetState = STATE_EXPANDED; 
     } 
    } else if (mHideable && shouldHide(child, getYVelocity())) { 
     top = mParentHeight; 
     targetState = STATE_HIDDEN; 
    } else if (mLastNestedScrollDy == 0) { 
     int currentTop = child.getTop(); 
     if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) { 
      top = mMinOffset; 
      targetState = STATE_EXPANDED; 
     } else { 
      top = mMaxOffset; 
      targetState = STATE_COLLAPSED; 
     } 
    } else { 
     //top = mMaxOffset; 
     //targetState = STATE_COLLAPSED; 
     int currentTop = child.getTop(); 
     if (currentTop > mAnchorPoint) { 
      top = mMaxOffset; 
      targetState = STATE_COLLAPSED; 
     } 
     else { 
      top = mAnchorPoint; 
      targetState = STATE_ANCHOR_POINT; 
     } 
    } 
    if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 
     setStateInternal(STATE_SETTLING); 
     ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState)); 
    } else { 
     setStateInternal(targetState); 
    } 
    mNestedScrolled = false; 
} 

public final void setState(@State int state) { 
    if (state == mState) { 
     return; 
    } 
    if (mViewRef == null) { 
     // The view is not laid out yet; modify mState and let onLayoutChild handle it later 
     /** 
     * New behavior (added: state == STATE_ANCHOR_POINT ||) 
     */ 
     if (state == STATE_COLLAPSED || state == STATE_EXPANDED || 
       state == STATE_ANCHOR_POINT || 
       (mHideable && state == STATE_HIDDEN)) { 
      mState = state; 
     } 
     return; 
    } 
    V child = mViewRef.get(); 
    if (child == null) { 
     return; 
    } 
    int top; 
    if (state == STATE_COLLAPSED) { 
     top = mMaxOffset; 
    } else if (state == STATE_ANCHOR_POINT) { 
     top = mAnchorPoint; 
    } else if (state == STATE_EXPANDED) { 
     top = mMinOffset; 
    } else if (mHideable && state == STATE_HIDDEN) { 
     top = mParentHeight; 
    } else { 
     throw new IllegalArgumentException("Illegal state argument: " + state); 
    } 
    setStateInternal(STATE_SETTLING); 
    if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) { 
     ViewCompat.postOnAnimation(child, new SettleRunnable(child, state)); 
    } 
} 


public static <V extends View> BottomSheetBehaviorGoogleMapsLike<V> from(V view) { 
    ViewGroup.LayoutParams params = view.getLayoutParams(); 
    if (!(params instanceof CoordinatorLayout.LayoutParams)) { 
     throw new IllegalArgumentException("The view is not a child of CoordinatorLayout"); 
    } 
    CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params) 
      .getBehavior(); 
    if (!(behavior instanceof BottomSheetBehaviorGoogleMapsLike)) { 
     throw new IllegalArgumentException(
       "The view is not associated with BottomSheetBehaviorGoogleMapsLike"); 
    } 
    return (BottomSheetBehaviorGoogleMapsLike<V>) behavior; 
} 



你甚至可以使用回調與behavior.setBottomSheetCallback(new BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback() {....

這裏是如何的模樣:
[CustomBottomSheetBehavior]

+0

謝謝,當我開始實施最終狀態時,我會研究這一點。不用複製/粘貼代碼就好了。如果可以以某種方式進行子類化,會更好,但可能需要代碼在子類中不可見。 –

+0

是的,我試圖繼承子類,但在%$#中很痛苦。現在我正在處理像谷歌地圖一樣的視差圖像效果。 – MiguelHincapieC

+0

@JeffLockhart我明白了!現在它與圖像視差效果和工具欄動畫一起工作......我只錯過了顏色,當你繼續向上滑動時,需要工具欄的顏色:D – MiguelHincapieC