2017-08-28 104 views
0

使用谷歌设计库BottomSheetBehavior,它看起来像默认行为是底部工作表“覆盖”在其扩展相同的CoordinatorLayout其他视图。我可以将类似FAB(或其他视图与适当定义的CoordinatorLayout.Behavior)的东西锚定到工作表的顶部,并在工作表展开时将其向上滑动,这很好,但我想要的是将视图“崩溃”为底部片材展开,显示视差效果。Android - 如何添加视差效果作为底部工作表覆盖另一个视图

谷歌地图中的这种效果与我所寻找的效果相似;它开始作为视差效应,然后切换回只是具有底片“盖”在地图一旦达到一定的滚动位置:

enter image description here

一件事我尝试(尽管我从一开始就被怀疑它不起作用),在我的BottomSheetBehavior.BottomSheetCallbackonSlide调用中以编程方式设置上视图的高度。这虽然有些成功,但运动并没有谷歌地图那么流畅。

如果有人有一个想法如何实现效果,我会很感激!

+0

一些[库](https://github.com/wasabeef/awesome-android-ui),它可以提供帮助。 –

回答

5

经过多一点实验/研究后,我从这篇文章中意识到 How to make custom CoordinatorLayout.Behavior with parallax scrolling effect for google MapView?我的问题的很大一部分并不了解视差效应,它翻译视图而不是缩小它们。一旦我意识到,这是微不足道的创建将适用视差我的主要观点自定义的行为,当下片扩展:

public class CollapseBehavior<V extends ViewGroup> extends CoordinatorLayout.Behavior<V>{ 


    public CollapseBehavior(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    } 

    @Override 
    public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) { 
    if (isBottomSheet(dependency)) { 
     BottomSheetBehavior behavior = ((BottomSheetBehavior) ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior()); 

     int peekHeight = behavior.getPeekHeight(); 
     // The default peek height is -1, which 
     // gets resolved to a 16:9 ratio with the parent 
     final int actualPeek = peekHeight >= 0 ? peekHeight : (int) (((parent.getHeight() * 1.0)/(16.0)) * 9.0); 
     if (dependency.getTop() >= actualPeek) { 
      // Only perform translations when the 
      // view is between "hidden" and "collapsed" states 
      final int dy = dependency.getTop() - parent.getHeight(); 
      ViewCompat.setTranslationY(child, dy/2); 
      return true; 
     } 
    } 

    return false; 
    } 

    private static boolean isBottomSheet(@NonNull View view) { 
    final ViewGroup.LayoutParams lp = view.getLayoutParams(); 
    if (lp instanceof CoordinatorLayout.LayoutParams) { 
     return ((CoordinatorLayout.LayoutParams) lp) 
       .getBehavior() instanceof BottomSheetBehavior; 
    } 
    return false; 
    } 


} 

然后在我的布局XML,我把我的主视图的app:layout_behavior到将com.mypackage.CollapseBehaviorapp:layout_anchor设置为我的底部工作表视图,以便触发onDependentViewChanged回调。这种效果比尝试调整视图更平滑。我怀疑返回到使用BottomSheetBehavior.BottomSheetCallback的初始策略也可以类似于此解决方案。

编辑:每个请求,相关的XML在下面。我在运行时将MapFragment添加到@+id/map_container中,但这应该也适用于像静态图像那样放入该容器的任何内容。该LocationListFragment同样可以与任何视图或片段取代,只要它仍然有BottomSheetBehavior

<android.support.design.widget.CoordinatorLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:id="@+id/fragment_coordinator"> 
     <FrameLayout 
      android:id="@+id/map_container" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_gravity="top" 
      app:layout_anchor="@+id/list_container" 
      app:layout_behavior="com.mypackage.behavior.CollapseBehavior"/> 

     <fragment 
      android:name="com.mypackage.fragment.LocationListFragment" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:id="@+id/list_container" 
      app:layout_behavior="android.support.design.widget.BottomSheetBehavior"/> 


    </android.support.design.widget.CoordinatorLayout> 
+0

我知道这是前一阵子,但是你是否介意为这个发布你的xml? – Pythogen

+1

没有问题!我已经添加了它 –

0

帕特里克·格雷森的职位是非常有益的。但就我而言,我确实需要调整地图的大小。我采用了上述解决方案来调整大小而不是翻译。也许其他人可能正在寻找类似的解决方案。

public class CollapseBehavior<V extends ViewGroup> extends CoordinatorLayout.Behavior<V> { 

private int pixels = NO_RESIZE_BUFFER; // default value, in case getting a value from resources bites the dust. 

private static final int NO_RESIZE_BUFFER = 200; //The amount of dp to not have the bottomsheet ever push away. 

public CollapseBehavior(Context context, AttributeSet attrs) 
{ 
    super(context, attrs); 
    pixels = (int)convertDpToPixel(NO_RESIZE_BUFFER,context); 
} 

@Override 
public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) { 
    // child is the map 
    // dependency is the bottomSheet 
    if(isBottomSheet(dependency)) 
    { 
     BottomSheetBehavior behavior = ((BottomSheetBehavior) ((CoordinatorLayout.LayoutParams)dependency.getLayoutParams()).getBehavior()); 

     int peekHeight; 
     if (behavior != null) { 
      peekHeight = behavior.getPeekHeight(); 
     } 
     else 
      return true; 

     if(peekHeight > 0) { // Dodge the case where the sheet is hidden. 

      if (dependency.getTop() >= peekHeight) { // Otherwise we'd completely overlap the map 

       if(dependency.getTop() >= pixels) { // On resize when we have more than our NO_RESIZE_BUFFER of dp left. 
        if(dependency.getTop() > 0) { // Don't want to map to be gone completely. 
         CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) child.getLayoutParams(); 
         params.height = dependency.getTop(); 
         child.setLayoutParams(params); 
        } 
        return true; 
       } 
      } 
     } 
    } 
    return false; 
} 

private static float convertDpToPixel(float dp, Context context) 
{ 
    float densityDpi = context.getResources().getDisplayMetrics().densityDpi; 
    return dp * (densityDpi/DisplayMetrics.DENSITY_DEFAULT); 
} 

private static boolean isBottomSheet(@NonNull View view) 
{ 
    final ViewGroup.LayoutParams lp = view.getLayoutParams(); 
    if(lp instanceof CoordinatorLayout.LayoutParams) 
    { 
     return ((CoordinatorLayout.LayoutParams) lp).getBehavior() instanceof BottomSheetBehavior; 
    } 
    return false; 
} 
} 

而且布局...

<FrameLayout 
    android:id="@+id/flMap" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_gravity="top" 
    android:layout_margin="0dp" 
    app:layout_anchor="@+id/persistentBottomSheet" 
    app:layout_behavior="com.yoursite.yourapp.CollapseBehavior"> 

    <fragment 
     android:id="@+id/mapDirectionSummary" 
     android:name="com.google.android.gms.maps.SupportMapFragment" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     tools:context="com.yoursite.yourapp.YourActivity" /> 

</FrameLayout> 

<android.support.constraint.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:id="@+id/persistentBottomSheet" 
app:behavior_peekHeight="@dimen/bottom_sheet_peek_height" 
app:behavior_hideable="false" 
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior" 
    tools:context="com.yoursite.yourapp.YourActivity"> 

<!-- Whatever you want in the bottom sheet. --> 

</android.support.constraint.ConstraintLayout> 

<LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"> 

    <android.support.v7.widget.CardView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_margin="8dp" 
     app:cardElevation="8dp" 
     app:cardBackgroundColor="#324"> 

     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="56dp" 
      android:background="?attr/colorPrimary" 
      android:theme="@style/ThemeOverlay.AppCompat.ActionBar" 
      app:popupTheme="@style/Theme.AppCompat.Light"> 

      <EditText 
       android:id="@+id/txtSearch" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:background="@android:color/transparent" 
       android:ems="10" 
       android:inputType="text" 
       android:maxLines="1" /> 


     </android.support.v7.widget.Toolbar> 
    </android.support.v7.widget.CardView> 


</LinearLayout> 
相关问题