Skip to content

Instantly share code, notes, and snippets.

@zly394
Last active April 4, 2024 12:13
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save zly394/6387f735d4161c625a06f5595c5cb8cd to your computer and use it in GitHub Desktop.
Save zly394/6387f735d4161c625a06f5595c5cb8cd to your computer and use it in GitHub Desktop.
Overscroll AppBarLayout Behavior—— AppBarLayout越界弹性效果
<?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"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay"
android:transitionName="picture"
app:layout_behavior="com.zly.exifviewer.widget.behavior.AppBarLayoutOverScrollViewBehavior"
tools:targetApi="lollipop">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentScrim="@color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
app:statusBarScrim="@color/colorPrimaryDark">
<ImageView
android:id="@+id/siv_picture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:foreground="@drawable/shape_fg_picture"
android:scaleType="centerCrop"
android:tag="overScroll"
app:layout_collapseMode="parallax"
tools:src="@android:drawable/sym_def_app_icon" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetEnd="64dp"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@mipmap/ic_launcher" />
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@mipmap/ic_launcher" />
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@mipmap/ic_launcher" />
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@mipmap/ic_launcher" />
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@mipmap/ic_launcher" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:clickable="true"
android:src="@drawable/ic_edit" />
</android.support.design.widget.CoordinatorLayout>
package com.zly.widget.behavior;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by zhuleiyue on 2017/3/7.
*/
public class AppBarLayoutOverScrollViewBehavior extends AppBarLayout.Behavior {
private static final String TAG = "overScroll";
private static final float TARGET_HEIGHT = 500;
private View mTargetView;
private int mParentHeight;
private int mTargetViewHeight;
private float mTotalDy;
private float mLastScale;
private int mLastBottom;
private boolean isAnimate;
public AppBarLayoutOverScrollViewBehavior() {
}
public AppBarLayoutOverScrollViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl, int layoutDirection) {
boolean handled = super.onLayoutChild(parent, abl, layoutDirection);
// 需要在调用过super.onLayoutChild()方法之后获取
if (mTargetView == null) {
mTargetView = parent.findViewWithTag(TAG);
if (mTargetView != null) {
initial(abl);
}
}
return handled;
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
isAnimate = true;
return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
if (mTargetView != null && ((dy < 0 && child.getBottom() >= mParentHeight) || (dy > 0 && child.getBottom() > mParentHeight))) {
scale(child, target, dy);
} else {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
}
}
@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY) {
if (velocityY > 100) {
isAnimate = false;
}
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl, View target) {
recovery(abl);
super.onStopNestedScroll(coordinatorLayout, abl, target);
}
private void initial(AppBarLayout abl) {
abl.setClipChildren(false);
mParentHeight = abl.getHeight();
mTargetViewHeight = mTargetView.getHeight();
}
private void scale(AppBarLayout abl, View target, int dy) {
mTotalDy += -dy;
mTotalDy = Math.min(mTotalDy, TARGET_HEIGHT);
mLastScale = Math.max(1f, 1f + mTotalDy / TARGET_HEIGHT);
ViewCompat.setScaleX(mTargetView, mLastScale);
ViewCompat.setScaleY(mTargetView, mLastScale);
mLastBottom = mParentHeight + (int) (mTargetViewHeight / 2 * (mLastScale - 1));
abl.setBottom(mLastBottom);
target.setScrollY(0);
}
private void recovery(final AppBarLayout abl) {
if (mTotalDy > 0) {
mTotalDy = 0;
if (isAnimate) {
ValueAnimator anim = ValueAnimator.ofFloat(mLastScale, 1f).setDuration(200);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
ViewCompat.setScaleX(mTargetView, value);
ViewCompat.setScaleY(mTargetView, value);
abl.setBottom((int) (mLastBottom - (mLastBottom - mParentHeight) * animation.getAnimatedFraction()));
}
});
anim.start();
} else {
ViewCompat.setScaleX(mTargetView, 1f);
ViewCompat.setScaleY(mTargetView, 1f);
abl.setBottom(mParentHeight);
}
}
}
}
@aSmartTortoise
Copy link

that is what i want , and wonderful

@shuangpinai
Copy link

great

@yuanlai0611
Copy link

This is fantastic!!!!!

@ZuJunJun
Copy link

ZuJunJun commented Aug 9, 2018

onStartNestedScroll、onNestedPreScroll、onStopNestedScroll was outdated, to lead the behavior was invalid,use the newest function was ok;
of me; thanks for your behavior;

@kibotu
Copy link

kibotu commented Jun 26, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment