Last active
February 15, 2021 17:04
-
-
Save MaciejKaras/02bff315f00b87d80467a470424f22c3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package pl.mkaras.utils; | |
import android.content.Context; | |
import android.support.design.widget.AppBarLayout; | |
import android.support.design.widget.CoordinatorLayout; | |
import android.support.v4.view.ViewCompat; | |
import android.support.v7.widget.Toolbar; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import java.util.List; | |
public class ScrollViewBehaviorFix extends AppBarLayout.ScrollingViewBehavior { | |
public ScrollViewBehaviorFix() { | |
super(); | |
} | |
public ScrollViewBehaviorFix(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
public boolean onMeasureChild(CoordinatorLayout parent, View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, | |
int heightUsed) { | |
if (child.getLayoutParams().height == -1) { | |
List<View> dependencies = parent.getDependencies(child); | |
if (dependencies.isEmpty()) { | |
return false; | |
} | |
final AppBarLayout appBar = findFirstAppBarLayout(dependencies); | |
if (appBar != null && ViewCompat.isLaidOut(appBar)) { | |
int availableHeight = View.MeasureSpec.getSize(parentHeightMeasureSpec); | |
if (availableHeight == 0) { | |
availableHeight = parent.getHeight(); | |
} | |
final int height = availableHeight - appBar.getMeasuredHeight(); | |
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST); | |
parent.onMeasureChild(child, parentWidthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed); | |
int childContentHeight = getContentHeight(child); | |
if (childContentHeight <= height) { | |
updateToolbar(parent, appBar, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed, false); | |
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); | |
parent.onMeasureChild(child, parentWidthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed); | |
return true; | |
} else { | |
updateToolbar(parent, appBar, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed, true); | |
return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); | |
} | |
} | |
} | |
return false; | |
} | |
private static int getContentHeight(View view) { | |
if (view instanceof ViewGroup) { | |
ViewGroup viewGroup = (ViewGroup) view; | |
int contentHeight = 0; | |
for (int index = 0; index < viewGroup.getChildCount(); ++index) { | |
View child = viewGroup.getChildAt(index); | |
contentHeight += child.getMeasuredHeight(); | |
} | |
return contentHeight; | |
} else { | |
return view.getMeasuredHeight(); | |
} | |
} | |
private static AppBarLayout findFirstAppBarLayout(List<View> views) { | |
int i = 0; | |
for (int z = views.size(); i < z; ++i) { | |
View view = views.get(i); | |
if (view instanceof AppBarLayout) { | |
return (AppBarLayout) view; | |
} | |
} | |
throw new IllegalArgumentException("Missing AppBarLayout in CoordinatorLayout dependencies"); | |
} | |
private void updateToolbar(CoordinatorLayout parent, AppBarLayout appBar, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, | |
int heightUsed, boolean toggle) { | |
toggleToolbarScroll(appBar, toggle); | |
appBar.forceLayout(); | |
parent.onMeasureChild(appBar, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); | |
} | |
private void toggleToolbarScroll(AppBarLayout appBar, boolean toggle) { | |
for (int index = 0; index < appBar.getChildCount(); ++index) { | |
View child = appBar.getChildAt(index); | |
if (child instanceof Toolbar) { | |
Toolbar toolbar = (Toolbar) child; | |
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams(); | |
int scrollFlags = params.getScrollFlags(); | |
if (toggle) { | |
scrollFlags |= AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL; | |
} else { | |
scrollFlags &= ~AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL; | |
} | |
params.setScrollFlags(scrollFlags); | |
} | |
} | |
} | |
} |
do you have working example of this code?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This behavior basically removes scroll flag
SCROLL
fromAppBarLayout
, when scrolling content in dependent view (RecyclerView
,NestedScrollView
) is less than view height, ie. when scrolling is not needed. It also overrides offsetting scrolling view, which is normally done byAppBarLayout.ScrollingViewBehavior
. Works well when adding footer, ie. button, to scrolling view or inViewPager
, where content length may be different in each page.