本文介绍了官方支持库23.x. + bottomSheet像谷歌地图一样滑动图片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 更新 我想完成与Google地图支持库23.x. +和没有任何第三个库的行为相同的行为 $ b 注意:这不是重复的问题,因为: 我想使用行为,支持库,没有任何第三方库(我在问题标题和以上描述中添加了它) 我想要所有行为,你在下一个gif中看到的,其他问题是要求一个或两个行为,并使用ANY WAY来实现它。 > 我已经使用官方的bottomSheet(即使在tab和view pager中)。 让我疯狂的是什么是如何使用官方bottomSheet向上滑动时实现从BottomSheet出现的图片行为。 我尝试过使用类似FAB的锚,但没有成功。 我阅读了一些关于使用滚动监听器的内容,但是ppl表示它不像Google Maps那样平滑和快速。 我的XML(我不认为它会帮忙,但无论如何): <?xml version =1.0encoding =utf-8?> < android.support.design.widget.CoordinatorLayout 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 =match_parent tools:context =。ui.MasterActivity> < android.support.design.widget.AppBarLayout android:layout_width =match_parent android:layout_height =wrap_content android:theme = @风格/ AppTheme.AppBarOverlay> < android.support.v7.widget.Toolbar android:id =@ + id / toolbar android:layout_width =match_parent android :layout_height =?attr / actionBarSize android:background =?attr / colorPrimary app:popupTheme =@ style / AppTheme.PopupOverlay app:layout_scrollFlags =scroll | enterAlways |啪> android:layout_width =wrap_content android:layout_height =wrap_content style =?android:attr / borderlessButtonStyle android:text =Departure android:layout_gravity =center android:id =@ + id / buttonToolBar /> < /android.support.v7.widget.Toolbar> < android.support.design.widget.TabLayout android:id =@ + id / tabs android:layout_width =match_parent android :layout_height =wrap_content app:tabBackground =@ android:color / white app:tabTextColor =@ color / colorAccent app:tabSelectedTextColor =@ color / colorAccent /> < /android.support.design.widget.AppBarLayout> < android.support.v4.view.ViewPager android:id =@ + id / viewpager android:layout_width =match_parent android :layout_height =match_parent app:layout_behavior =@ string / appbar_scrolling_view_behavior/> < android.support.v4.widget.NestedScrollView android:id =@ + id / asdf android:layout_width =match_parent android:layout_height =match_parent android:orientation =vertical app:behavior_peekHeight =100dp android:fitsSystemWindows =true app:layout_behavior = android.support.design.widget.BottomSheetBehavior > < LinearLayout android:id =@ + id / qwert android:layout_width =match_parent android:layout_height =match_parent android:orientation =vertical android:paddingBottom =16dp android:background =@ android:color / white android:padding =15dp> < TextView android:layout_width =match_parent android:layout_height =wrap_content android:text =BOOTOMSHEET TITLE android :textAppearance =@ style / TextAppearance.AppCompat.Title/> < Button android:layout_width =match_parent android:layout_height =wrap_content android:text =Button1/> < TextView android:layout_width =match_parent android:layout_height =wrap_content android:text =text 2 android :layout_margin = 10dp/> < TextView android:layout_width =match_parent android:layout_height =wrap_content android:text =text 3 android :layout_margin = 10dp/> < TextView android:layout_width =match_parent android:layout_height =wrap_content android:text =text 4 android :layout_margin = 10dp/> $ b< FrameLayout android:layout_width =match_parent android:layout_height =320dp android:background =@ color / colorAccent > < TextView android:layout_width =wrap_content android:layout_height =wrap_content android:layout_gravity =center android: text =你的剩余内容在这里 android:textColor =@ android:color / white/> < / FrameLayout> < / LinearLayout> < /android.support.v4.widget.NestedScrollView> < android.support.design.widget.FloatingActionButton android:layout_height =wrap_content android:layout_width =wrap_content app :layout_anchor =@ id / asdf app:layout_anchorGravity =top | right | end android:src =@ drawable / abc_ic_search_api_mtrl_alpha_copy android:layout_margin =@ dimen / fab_margin android:clickable =true/> 解决方案如果您想使用Support Library 23.4来实现它。 0. +我会告诉你我是如何得到它以及它是如何工作的。 注意:我为我的英语道歉,我试图给编程的答案(只是简短的和有用的代码混合),但似乎它不够好...... 到目前为止,我可以看到活动/片段具有以下行为: 2个带动画的工具栏,可响应底部表单移动。 它靠近模式工具栏(当您向上滑动时出现的那个)。 底部表单背后的背景图像,带有某种视差效果。 工具栏中的标题(TextView)在底部工作表到达时显示。 通知satus栏可将其背景变为透明或全彩。 具有锚点状态的自定义底部表单行为。 note2:这个回答谈论6件事不像其他问题那样大概1或2,你现在能看出差异吗? 好吧,现在我们来看一下再见: 工具栏 当您在Google地图中打开该视图时,您可以在可搜索的位置看到一个工具栏,这是我唯一没有做过的工作就像谷歌地图一样,因为我想更通用一些。无论如何, ToolBar 位于 AppBarLayout 中,当您开始拖动BottomSheet时它会隐藏起来,而当BottomSheet达到 COLLAPSED 状态。 要实现它,您需要: 创建一个行为,并从 AppBarLayout.ScrollingViewBehavior 覆盖 layoutDependsOn 和 onDependentViewChanged 方法。做到这一点,您将听取bottomSheet的动作。 创建一些方法来隐藏和取消隐藏带动画的AppBarLayout / ToolBar。 ul> 这是我为第一个工具栏或ActionBar所做的工作: @Override public boolean layoutDependsOn(CoordinatorLayout parent,View child,View dependency){返回依赖关系instanceof NestedScrollView; $ b @Override public boolean onDependentViewChanged(CoordinatorLayout parent,View child, View dependency){ if(mChild == null){ initValues(child,dependency); 返回false; } float dVerticalScroll = dependency.getY() - mPreviousY; mPreviousY = dependency.getY(); //如果(dVerticalScroll< = 0&&!hidden){ dismissAppBar(child); 返回true; } return false; private void initValues(final View child,View dependency){ mChild = child; mInitialY = child.getY(); BottomSheetBehaviorGoogleMapsLike bottomSheetBehavior = BottomSheetBehaviorGoogleMapsLike.from(dependency); bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback(){ @Override $ b $ public void onStateChanged(@NonNull查看bottomSheet,@ BottomSheetBehaviorGoogleMapsLike.State int newState){ if(newState = = BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED || newState == BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN) showAppBar(child); } $ b $ @Override public void onSlide(@ NonNull查看bottomSheet,float slideOffset){ } }); } private void dismissAppBar(View child){ hidden = true; AppBarLayout appBarLayout =(AppBarLayout)子项; mToolbarAnimation = appBarLayout.animate()。setDuration(mContext.getResources()。getInteger(android.R.integer.config_shortAnimTime)); mToolbarAnimation.y( - (mChild.getHeight()+ 25))。start(); } private void showAppBar(View child){ hidden = false; AppBarLayout appBarLayout =(AppBarLayout)子项; mToolbarAnimation = appBarLayout.animate()。setDuration(mContext.getResources()。getInteger(android.R.integer.config_mediumAnimTime)); mToolbarAnimation.y(mInitialY).start(); } 如果您需要它的完整文件 第二个工具栏或Modal工具栏: 您必须重写相同的方法,但在这一个中您必须关注更多的行为: $ b 显示/隐藏带动画的工具栏 更改动态栏颜色/背景 显示/隐藏ToolBar中的BottomSheet标题 关闭bottomSheet或将其发送到折叠状态 这个代码有点广泛,所以我会让链接 FAB 这也是自定义行为,但是从 FloatingActionButton.Behavior 扩展。在 onDependentViewChanged 中,当它到达offSet或你想隐藏的地方时,你必须看看它。在我的情况下,我想隐藏它靠近第二个工具栏,所以我深入到FAB父(CoordiantorLayout)寻找包含ToolBar的AppBarLayout,然后使用ToolBar位置,如 OffSet $ b $ $ $ $ $ $ $ $ $ $ $ $ $ $ $公共布尔onDependentViewChanged(CoordinatorLayout parent,FloatingActionButton child,View依赖项){ if(offset == 0) setOffsetValue(parent); if(dependency.getY() return false; if(child.getY()< =(offset + child.getHeight())&& child.getVisibility()== View.VISIBLE) child.hide( ); else if(child.getY()> offset&& child.getVisibility()!= View.VISIBLE) child.show(); 返回false; } 完整的自定义FAB行为链接 具有视差效果的底部图片背后的图片: 与其他图片一样,它是一种自定义行为,其中唯一复杂的东西是小算法这样可以将图像保持在BottomSheet中,并避免像默认视差效果那样的图像崩溃: $ $ p $ code @Override public boolean onDependentViewChanged(CoordinatorLayout parent,View child, View dependency){ if(mYmultiplier == 0){ initValues(child,dependency); 返回true; } float dVerticalScroll = dependency.getY() - mPreviousY; mPreviousY = dependency.getY(); //如果(dVerticalScroll child.setY(0); 返回true; (dVerticalScroll> = 0&& dependency.getY()< = mImageHeight)返回false; //下降。 child.setY((int)(child.getY()+(dVerticalScroll * mYmultiplier))); 返回true; } 背景图片的完整文件带有视差效果的图片 现在结束:自定义底部行为 要实现3个步骤首先你需要明白默认的BottomSheetBehavior有5个状态: STATE_DRAGGING,STATE_SETTLING,STATE_EXPANDED,STATE_COLLAPSED,STATE_HIDDEN ,对于谷歌地图行为,你需要在折叠和展开: STATE_ANCHOR_POINT 。 我试着扩展了默认的bottomSheetBehavior没有成功,所以我只是复制粘贴所有代码并修改了我需要的内容。 为了实现我在说的内容,请遵循以下步骤: 创建一个Java类并从 CoordinatorLayout.Behavior< V> 将粘贴代码从默认 BottomSheetBehavior 使用以下代码修改方法 clampViewPositionVertical : @Override public int clampViewPositionVertical(View child,int top,int dy){ return constrain(top,mMinOffset,mHideable? mParentHeight:mMaxOffset); } int constrain(int amount,int low,int high){ return amount<低?低:(量>高→高:量); } 添加新状态 public static final int STATE_ANCHOR_POINT = X; 修改下面的方法: onLayoutChild , onStopNestedScroll , BottomSheetBehavior< V>从(V视图)和 setState (可选) $ $ b public boolean onLayoutChild(CoordinatorLayout parent,V child,int layoutDirection) { //如果(mState!= STATE_DRAGGING&& mState!= STATE_SETTLING){ if(ViewCompat.getFitsSystemWindows(parent)&& !ViewCompat.getFitsSystemWindows(child)){ ViewCompat.setFitsSystemWindows(child,true); } parent.onLayoutChild(child,layoutDirection); } //抵消底部表单 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); $ b $如果(mHateable& 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; } 其他{ top = mMinOffset; targetState = STATE_EXPANDED; } } else if(mHideable&& shouldHide(child,getYVelocity())){ top = mParentHeight; targetState = STATE_HIDDEN; } else if(mLastNestedScrollDy == 0){ int currentTop = child.getTop(); (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; $ b 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){ //视图尚未布置;修改mState并让onLayoutChild稍后处理它 / ** *新行为(添加: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(视图不是CoordinatorLayout的子项); } CoordinatorLayout.Behavior behavior =((CoordinatorLayout.LayoutParams)params) .getBehavior(); if(!(behavior of instance of BottomSheetBehaviorGoogleMapsLike)){ throw new IllegalArgumentException(该视图与BottomSheetBehaviorGoogleMapsLike无关); } return(BottomSheetBehaviorGoogleMapsLike< V>)行为; } 链接到洞项目,您可以在其中查看所有自定义行为 note3:下一次添加评论时要求以礼貌的方式更改答案,或者问为什么这个答案有一些等于其他人的答案我的同一主题的答案在关闭它或标记之前喜欢重复。 以下是它的样子: [] UpdateI want to accomplish the same behavior that google maps has with Support Library 23.x.+ and without ANY 3rd libraryNOTE: this in not a duplicated question because:I want to use Behaviors, Support Library and without ANY 3rd party library (I added it in question title and above description)I wanted ALL behaviors that you see in next gif, the other questions are asking for one or two behaviors and using ANY WAY to achieve it.I have already the Official bottomSheet working (even inside a tab and view pager).What is making me going crazy is how to achieve the image behavior that come up from the BottomSheet when sliding up using official bottomSheet?.I have tried using anchor like FAB with no success.I read something about using a scroll listener but ppl said its not smooth and faster like google maps.My XML (I don't think its going to help but anyway):<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout 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="match_parent" tools:context=".ui.MasterActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" app:layout_scrollFlags="scroll|enterAlways|snap"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" style="?android:attr/borderlessButtonStyle" android:text="Departure" android:layout_gravity="center" android:id="@+id/buttonToolBar" /> </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabBackground="@android:color/white" app:tabTextColor="@color/colorAccent" app:tabSelectedTextColor="@color/colorAccent"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <android.support.v4.widget.NestedScrollView android:id="@+id/asdf" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:behavior_peekHeight="100dp" android:fitsSystemWindows="true" app:layout_behavior="android.support.design.widget.BottomSheetBehavior"> <LinearLayout android:id="@+id/qwert" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="16dp" android:background="@android:color/white" android:padding="15dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="BOOTOMSHEET TITLE" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button1"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="text 2" android:layout_margin="10dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="text 3" android:layout_margin="10dp"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="text 4" android:layout_margin="10dp"/> <FrameLayout android:layout_width="match_parent" android:layout_height="320dp" android:background="@color/colorAccent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Your remaining content here" android:textColor="@android:color/white" /> </FrameLayout> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_height="wrap_content" android:layout_width="wrap_content" app:layout_anchor="@id/asdf" app:layout_anchorGravity="top|right|end" android:src="@drawable/abc_ic_search_api_mtrl_alpha_copy" android:layout_margin="@dimen/fab_margin" android:clickable="true"/></android.support.design.widget.CoordinatorLayout> 解决方案 If you want to achieve it using Support Library 23.4.0.+ I will tell you how I got it and how its works.note: my apologize for my english, I tried to give a programming answer (just short and mixed with useful code) but seem like it was not good enough...As far I can see that activity/fragment has the followings behaviors:2 toolbars with animations that respond to the bottom sheet movements.A FAB that hides when it is near to the "modal toolbar" (the one that appears when you are sliding up).A backdrop image behind bottom sheet with some kind of parallax effect.A Title (TextView) in Toolbar that appears when bottom sheet reach it.The notification satus bar can turn its background to transparent or full color.A custom bottom sheet behavior with an "anchor" state.note2: This answer talk about 6 things not about 1 or 2 like other question, can you see the difference now?Ok, now let's check one bye one:ToolBarsWhen you open that view in google maps u can see a toolbar in where you can search, it's the only one that I'm not doing equals like google maps, because I wanted to do it more generic. Anyway that ToolBar is inside an AppBarLayout and it got hidden when you start dragging the BottomSheet and it appears again when the BottomSheet reach the COLLAPSED state.To achieve it you need:create a Behavior and extend it from AppBarLayout.ScrollingViewBehavioroverride layoutDependsOn and onDependentViewChanged methods. Doing it you will listen for bottomSheet movements.create some methods to hide and unhide the AppBarLayout/ToolBar with animations.This is how I did it for first toolbar or ActionBar:@Overridepublic boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof NestedScrollView;}@Overridepublic boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { if (mChild == null) { initValues(child, dependency); return false; } float dVerticalScroll = dependency.getY() - mPreviousY; mPreviousY = dependency.getY(); //going up if (dVerticalScroll <= 0 && !hidden) { dismissAppBar(child); return true; } return false;}private void initValues(final View child, View dependency) { mChild = child; mInitialY = child.getY(); BottomSheetBehaviorGoogleMapsLike bottomSheetBehavior = BottomSheetBehaviorGoogleMapsLike.from(dependency); bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehaviorGoogleMapsLike.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, @BottomSheetBehaviorGoogleMapsLike.State int newState) { if (newState == BottomSheetBehaviorGoogleMapsLike.STATE_COLLAPSED || newState == BottomSheetBehaviorGoogleMapsLike.STATE_HIDDEN) showAppBar(child); } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { } });}private void dismissAppBar(View child){ hidden = true; AppBarLayout appBarLayout = (AppBarLayout)child; mToolbarAnimation = appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_shortAnimTime)); mToolbarAnimation.y(-(mChild.getHeight()+25)).start();}private void showAppBar(View child) { hidden = false; AppBarLayout appBarLayout = (AppBarLayout)child; mToolbarAnimation = appBarLayout.animate().setDuration(mContext.getResources().getInteger(android.R.integer.config_mediumAnimTime)); mToolbarAnimation.y(mInitialY).start();}the complete file if you need itThe second Toolbar or "Modal" toolbar:You have to override same methods but in this one you have to take care about more behaviors:show/hide the ToolBar with animationschange statur bar color/backgroundshow/hide the BottomSheet title in the ToolBarclose the bottomSheet or send it to collapsed stateThe code for this one is a little extensive so I will let the linkThe FABThis is a Custom Behavior too but extends from FloatingActionButton.Behavior. In onDependentViewChanged you have to look when it reach the "offSet" or point in where you want to hide it. In my case I want hide it when its near to the second toolbar, so I dig into FAB parent (a CoordiantorLayout) looking for the AppBarLayout that contains the ToolBar, then I use the ToolBar position like OffSet:@Overridepublic boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) { if (offset == 0) setOffsetValue(parent); if (dependency.getY() <=0) return false; if (child.getY() <= (offset + child.getHeight()) && child.getVisibility() == View.VISIBLE) child.hide(); else if (child.getY() > offset && child.getVisibility() != View.VISIBLE) child.show(); return false;}Complete Custom FAB Behavior linkThe Image behind the BottomSheet with parallax effect:Like the others its a custom behavior, the only "complicated" thing in this one is the little algorithm that keeps the Image anchored to the BottomSheet and avoid the image collapse like default parallax effect:@Overridepublic boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { if (mYmultiplier == 0) { initValues(child, dependency); return true; } float dVerticalScroll = dependency.getY() - mPreviousY; mPreviousY = dependency.getY(); //going up if (dVerticalScroll <= 0 && child.getY() <= 0) { child.setY(0); return true; } //going down if (dVerticalScroll >= 0 && dependency.getY() <= mImageHeight) return false; child.setY( (int)(child.getY() + (dVerticalScroll * mYmultiplier) ) ); return true;}complete file for backdrop Image with parallax effectNow for the end: The Custom BottomSheet BehaviorTo achieve the 3 steps first you need to understant that default BottomSheetBehavior has 5 states: STATE_DRAGGING, STATE_SETTLING, STATE_EXPANDED, STATE_COLLAPSED, STATE_HIDDEN and for the Google Maps behavior you need to add a middle state between collapsed and expanded: STATE_ANCHOR_POINT.I tried extends the default bottomSheetBehavior with no success, so I just copy paste all code and modified what I need.To achieve what I'm talking about follow the next steps:Create a Java class and extend it from CoordinatorLayout.Behavior<V>Copy paste code from default BottomSheetBehavior file to your new one.Modify the method clampViewPositionVertical with the following code:@Overridepublic int clampViewPositionVertical(View child, int top, int dy) { return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);}int constrain(int amount, int low, int high) { return amount < low ? low : (amount > high ? high : amount);}Add a new statepublic static final int STATE_ANCHOR_POINT = X;Modify the next methods: onLayoutChild, onStopNestedScroll, BottomSheetBehavior<V> from(V view) and setState (optional)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;}link to the hole project in where you can see all Custom Behaviorsnote3: next time add a comment asking in a polite way for change of the answer or ask why this answer has SOME equals stuff than others answer of mine about same topic BEFORE close it or mark like duplicated.And here is how its looks like:[] 这篇关于官方支持库23.x. + bottomSheet像谷歌地图一样滑动图片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 09-09 09:24