Merge "Use StateListAnimator for AppBarLayout elevation changes" into nyc-dev

GitOrigin-RevId=cb849a71706ac0660a5383c11629bc8d9c1a9f28

PiperOrigin-RevId: 140560610
This commit is contained in:
Chris Banes 2016-11-30 04:03:04 +00:00 committed by Travis Collins
parent ac75324568
commit a03cca4fb7
12 changed files with 334 additions and 96 deletions

View File

@ -4,12 +4,12 @@ package android.support.design.widget {
ctor public AppBarLayout(android.content.Context);
ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
method public float getTargetElevation();
method public deprecated float getTargetElevation();
method public final int getTotalScrollRange();
method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
method public void setExpanded(boolean);
method public void setExpanded(boolean, boolean);
method public void setTargetElevation(float);
method public deprecated void setTargetElevation(float);
}
public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {

View File

@ -16,13 +16,65 @@
package android.support.design.widget;
import android.animation.AnimatorInflater;
import android.animation.ObjectAnimator;
import android.animation.StateListAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.R;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
class ViewUtilsLollipop {
private static final int[] STATE_LIST_ANIM_ATTRS = new int[] {android.R.attr.stateListAnimator};
static void setBoundsViewOutlineProvider(View view) {
view.setOutlineProvider(ViewOutlineProvider.BOUNDS);
}
static void setStateListAnimatorFromAttrs(View view, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
final Context context = view.getContext();
final TypedArray a = context.obtainStyledAttributes(attrs, STATE_LIST_ANIM_ATTRS,
defStyleAttr, defStyleRes);
try {
if (a.hasValue(0)) {
StateListAnimator sla = AnimatorInflater.loadStateListAnimator(context,
a.getResourceId(0, 0));
view.setStateListAnimator(sla);
}
} finally {
a.recycle();
}
}
/**
* Creates and sets a {@link StateListAnimator} with a custom elevation value
*/
static void setDefaultAppBarLayoutStateListAnimator(final View view,
final float targetElevation) {
final StateListAnimator sla = new StateListAnimator();
// Enabled, collapsible and collapsed == elevated
sla.addState(new int[]{android.R.attr.enabled, R.attr.state_collapsible,
R.attr.state_collapsed},
ObjectAnimator.ofFloat(view, "elevation", targetElevation));
// Enabled and collapsible, but not collapsed != elevated
sla.addState(new int[]{android.R.attr.enabled, R.attr.state_collapsible,
-R.attr.state_collapsed},
ObjectAnimator.ofFloat(view, "elevation", 0f));
// Enabled but not collapsible == elevated
sla.addState(new int[]{android.R.attr.enabled, -R.attr.state_collapsible},
ObjectAnimator.ofFloat(view, "elevation", targetElevation));
// Default, none elevated state
sla.addState(new int[0], ObjectAnimator.ofFloat(view, "elevation", 0));
view.setStateListAnimator(sla);
}
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:state_enabled="true" app:state_collapsible="true" app:state_collapsed="true">
<objectAnimator android:propertyName="elevation"
android:valueTo="@dimen/design_appbar_elevation"
android:valueType="floatType"/>
</item>
<item android:state_enabled="true" app:state_collapsible="true" app:state_collapsed="false">
<objectAnimator android:propertyName="elevation"
android:valueTo="0dp"
android:valueType="floatType"/>
</item>
<item android:state_enabled="true" app:state_collapsible="false">
<objectAnimator android:propertyName="elevation"
android:valueTo="@dimen/design_appbar_elevation"
android:valueType="floatType"/>
</item>
<item>
<objectAnimator android:propertyName="elevation"
android:valueTo="0"
android:valueType="floatType"/>
</item>
</selector>

24
res/values-v21/styles.xml Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2016 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<resources>
<style name="Widget.Design.AppBarLayout" parent="Base.Widget.Design.AppBarLayout">
<item name="android:stateListAnimator">@anim/design_appbar_state_list_animator</item>
</style>
</resources>

View File

@ -210,6 +210,7 @@
</declare-styleable>
<declare-styleable name="AppBarLayout">
<!-- Deprecated. Elevation is now controlled via a state list animator. -->
<attr name="elevation" />
<attr name="android:background" />
<!-- The initial expanded state for the AppBarLayout. This only takes effect when this
@ -217,6 +218,15 @@
<attr name="expanded" format="boolean" />
</declare-styleable>
<declare-styleable name="AppBarLayoutStates">
<!-- State value for {@link android.support.design.widget.AppBarLayout} set when the view
has been collapsed. -->
<attr name="state_collapsed" format="boolean" />
<!-- State value for {@link android.support.design.widget.AppBarLayout} set when the view
has children which are capable of being collapsed. -->
<attr name="state_collapsible" format="boolean" />
</declare-styleable>
<declare-styleable name="AppBarLayout_LayoutParams">
<attr name="layout_scrollFlags">
<!-- The view will be scroll in direct relation to scroll events. This flag needs to be

View File

@ -101,11 +101,13 @@
<item name="statusBarScrim">?attr/colorPrimaryDark</item>
</style>
<style name="Widget.Design.AppBarLayout" parent="android:Widget">
<item name="elevation">@dimen/design_appbar_elevation</item>
<style name="Base.Widget.Design.AppBarLayout" parent="android:Widget">
<item name="android:background">?attr/colorPrimary</item>
</style>
<style name="Widget.Design.AppBarLayout" parent="Base.Widget.Design.AppBarLayout">
</style>
<style name="Widget.Design.CoordinatorLayout" parent="android:Widget">
<item name="statusBarBackground">?attr/colorPrimaryDark</item>
</style>

View File

@ -18,6 +18,7 @@ package android.support.design.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.IntDef;
@ -124,15 +125,18 @@ public class AppBarLayout extends LinearLayout {
private int mDownPreScrollRange = INVALID_SCROLL_RANGE;
private int mDownScrollRange = INVALID_SCROLL_RANGE;
boolean mHaveChildWithInterpolator;
private float mTargetElevation;
private boolean mHaveChildWithInterpolator;
private int mPendingAction = PENDING_ACTION_NONE;
private WindowInsetsCompat mLastInsets;
private final List<OnOffsetChangedListener> mListeners;
private List<OnOffsetChangedListener> mListeners;
private boolean mCollapsible;
private boolean mCollapsed;
private final int[] mTmpStatesArray = new int[2];
public AppBarLayout(Context context) {
this(context, null);
@ -144,22 +148,29 @@ public class AppBarLayout extends LinearLayout {
ThemeUtils.checkAppCompatTheme(context);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
if (Build.VERSION.SDK_INT >= 21) {
// Use the bounds view outline provider so that we cast a shadow, even without a
// background
ViewUtilsLollipop.setBoundsViewOutlineProvider(this);
// If we're running on API 21+, we should reset any state list animator from our
// default style
ViewUtilsLollipop.setStateListAnimatorFromAttrs(this, attrs, 0,
R.style.Widget_Design_AppBarLayout);
}
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
0, R.style.Widget_Design_AppBarLayout);
mTargetElevation = a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0);
setBackgroundDrawable(a.getDrawable(R.styleable.AppBarLayout_android_background));
if (a.hasValue(R.styleable.AppBarLayout_expanded)) {
setExpanded(a.getBoolean(R.styleable.AppBarLayout_expanded, false));
}
if (Build.VERSION.SDK_INT >= 21 && a.hasValue(R.styleable.AppBarLayout_elevation)) {
ViewUtilsLollipop.setDefaultAppBarLayoutStateListAnimator(
this, a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0));
}
a.recycle();
// Use the bounds view outline provider so that we cast a shadow, even without a background
ViewUtils.setBoundsViewOutlineProvider(this);
mListeners = new ArrayList<>();
ViewCompat.setElevation(this, mTargetElevation);
ViewCompat.setOnApplyWindowInsetsListener(this,
new android.support.v4.view.OnApplyWindowInsetsListener() {
@Override
@ -178,6 +189,9 @@ public class AppBarLayout extends LinearLayout {
* @see #removeOnOffsetChangedListener(OnOffsetChangedListener)
*/
public void addOnOffsetChangedListener(OnOffsetChangedListener listener) {
if (mListeners == null) {
mListeners = new ArrayList<>();
}
if (listener != null && !mListeners.contains(listener)) {
mListeners.add(listener);
}
@ -189,7 +203,7 @@ public class AppBarLayout extends LinearLayout {
* @param listener the listener to remove.
*/
public void removeOnOffsetChangedListener(OnOffsetChangedListener listener) {
if (listener != null) {
if (mListeners != null && listener != null) {
mListeners.remove(listener);
}
}
@ -216,6 +230,19 @@ public class AppBarLayout extends LinearLayout {
break;
}
}
updateCollapsible();
}
private void updateCollapsible() {
boolean haveCollapsibleChild = false;
for (int i = 0, z = getChildCount(); i < z; i++) {
if (((LayoutParams) getChildAt(i).getLayoutParams()).isCollapsible()) {
haveCollapsibleChild = true;
break;
}
}
setCollapsible(haveCollapsibleChild);
}
private void invalidateScrollRanges() {
@ -422,6 +449,19 @@ public class AppBarLayout extends LinearLayout {
return mDownScrollRange = Math.max(0, range);
}
private void dispatchOffsetUpdates(int offset) {
// Iterate backwards through the list so that most recently added listeners
// get the first chance to decide
if (mListeners != null) {
for (int i = 0, z = mListeners.size(); i < z; i++) {
final OnOffsetChangedListener listener = mListeners.get(i);
if (listener != null) {
listener.onOffsetChanged(this, offset);
}
}
}
}
final int getMinimumHeightForVisibleOverlappingContent() {
final int topInset = getTopInset();
final int minHeight = ViewCompat.getMinimumHeight(this);
@ -437,28 +477,54 @@ public class AppBarLayout extends LinearLayout {
: 0;
}
/**
* Set the elevation value to use when this {@link AppBarLayout} should be elevated
* above content.
* <p>
* This method does not do anything itself. A typical use for this method is called from within
* an {@link OnOffsetChangedListener} when the offset has changed in such a way to require an
* elevation change.
*
* @param elevation the elevation value to use.
*
* @see ViewCompat#setElevation(View, float)
*/
public void setTargetElevation(float elevation) {
mTargetElevation = elevation;
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] extraStates = mTmpStatesArray;
final int[] states = super.onCreateDrawableState(extraSpace + extraStates.length);
extraStates[0] = mCollapsible ? R.attr.state_collapsible : -R.attr.state_collapsible;
extraStates[1] = mCollapsible && mCollapsed
? R.attr.state_collapsed : -R.attr.state_collapsed;
return mergeDrawableStates(states, extraStates);
}
private void setCollapsible(boolean collapsible) {
if (mCollapsible != collapsible) {
mCollapsible = collapsible;
refreshDrawableState();
}
}
private void setCollapsed(boolean collapsed) {
if (mCollapsed != collapsed) {
mCollapsed = collapsed;
refreshDrawableState();
}
}
/**
* Returns the elevation value to use when this {@link AppBarLayout} should be elevated
* above content.
* @deprecated target elevation is now deprecated. AppBarLayout's elevation is now
* controlled via a {@link StateListAnimator}. If a target elevation is set, either by this
* method or the {@code app:elevation} attibute, a new state list animator is created which
* uses the given {@code elevation} value.
*
* @attr ref android.support.design.R.styleable#AppBarLayout_elevation
*/
@Deprecated
public void setTargetElevation(float elevation) {
if (Build.VERSION.SDK_INT >= 21) {
ViewUtilsLollipop.setDefaultAppBarLayoutStateListAnimator(this, elevation);
}
}
/**
* @deprecated target elevation is now deprecated. AppBarLayout's elevation is now
* controlled via a {@link StateListAnimator}. This method now always returns 0.
*/
@Deprecated
public float getTargetElevation() {
return mTargetElevation;
return 0;
}
private int getPendingAction() {
@ -550,6 +616,8 @@ public class AppBarLayout extends LinearLayout {
*/
static final int FLAG_QUICK_RETURN = SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS;
static final int FLAG_SNAP = SCROLL_FLAG_SCROLL | SCROLL_FLAG_SNAP;
static final int COLLAPSIBLE_FLAGS = SCROLL_FLAG_EXIT_UNTIL_COLLAPSED
| SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED;
int mScrollFlags = SCROLL_FLAG_SCROLL;
Interpolator mScrollInterpolator;
@ -643,6 +711,14 @@ public class AppBarLayout extends LinearLayout {
public Interpolator getScrollInterpolator() {
return mScrollInterpolator;
}
/**
* Returns true if the scroll flags are compatible for 'collapsing'
*/
private boolean isCollapsible() {
return (mScrollFlags & SCROLL_FLAG_SCROLL) == SCROLL_FLAG_SCROLL
&& (mScrollFlags & COLLAPSIBLE_FLAGS) != 0;
}
}
/**
@ -938,8 +1014,8 @@ public class AppBarLayout extends LinearLayout {
setTopAndBottomOffset(
MathUtils.constrain(getTopAndBottomOffset(), -abl.getTotalScrollRange(), 0));
// Make sure we update the elevation
dispatchOffsetUpdates(abl);
// Make sure we dispatch the offset update
abl.dispatchOffsetUpdates(getTopAndBottomOffset());
return handled;
}
@ -995,7 +1071,7 @@ public class AppBarLayout extends LinearLayout {
? interpolateOffset(appBarLayout, newOffset)
: newOffset;
boolean offsetChanged = setTopAndBottomOffset(interpolatedOffset);
final boolean offsetChanged = setTopAndBottomOffset(interpolatedOffset);
// Update how much dy we have consumed
consumed = curOffset - newOffset;
@ -1011,7 +1087,11 @@ public class AppBarLayout extends LinearLayout {
}
// Dispatch the updates to any listeners
dispatchOffsetUpdates(appBarLayout);
appBarLayout.dispatchOffsetUpdates(getTopAndBottomOffset());
// Update the AppBarLayout's drawable state (for any elevation changes)
updateAppBarLayoutDrawableState(appBarLayout, newOffset,
newOffset < curOffset ? -1 : 1);
}
} else {
// Reset the offset delta
@ -1021,19 +1101,6 @@ public class AppBarLayout extends LinearLayout {
return consumed;
}
private void dispatchOffsetUpdates(AppBarLayout layout) {
final List<OnOffsetChangedListener> listeners = layout.mListeners;
// Iterate backwards through the list so that most recently added listeners
// get the first chance to decide
for (int i = 0, z = listeners.size(); i < z; i++) {
final OnOffsetChangedListener listener = listeners.get(i);
if (listener != null) {
listener.onOffsetChanged(layout, getTopAndBottomOffset());
}
}
}
private int interpolateOffset(AppBarLayout layout, final int offset) {
final int absOffset = Math.abs(offset);
@ -1081,6 +1148,44 @@ public class AppBarLayout extends LinearLayout {
return offset;
}
private void updateAppBarLayoutDrawableState(final AppBarLayout layout,
final int offset, final int direction) {
final View child = getAppBarChildOnOffset(layout, offset);
if (child != null) {
final AppBarLayout.LayoutParams childLp = (LayoutParams) child.getLayoutParams();
final int flags = childLp.getScrollFlags();
boolean collapsed = false;
if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
final int minHeight = ViewCompat.getMinimumHeight(child);
if (direction > 0 && (flags & (LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
| LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED)) != 0) {
// We're set to enter always collapsed so we are only collapsed when
// being scrolled down, and in a collapsed offset
collapsed = -offset >= child.getBottom() - minHeight - layout.getTopInset();
} else if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
// We're set to exit until collapsed, so any offset which results in
// the minimum height (or less) being shown is collapsed
collapsed = -offset >= child.getBottom() - minHeight - layout.getTopInset();
}
}
layout.setCollapsed(collapsed);
}
}
private static View getAppBarChildOnOffset(final AppBarLayout layout, final int offset) {
final int absOffset = Math.abs(offset);
for (int i = 0, z = layout.getChildCount(); i < z; i++) {
final View child = layout.getChildAt(i);
if (absOffset >= child.getTop() && absOffset <= child.getBottom()) {
return child;
}
}
return null;
}
@Override
int getTopBottomOffsetForScrollingSibling() {
return getTopAndBottomOffset() + mOffsetDelta;

View File

@ -1117,7 +1117,6 @@ public class CollapsingToolbarLayout extends FrameLayout {
mCurrentOffset = verticalOffset;
final int insetTop = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
final int scrollRange = layout.getTotalScrollRange();
for (int i = 0, z = getChildCount(); i < z; i++) {
final View child = getChildAt(i);
@ -1151,15 +1150,6 @@ public class CollapsingToolbarLayout extends FrameLayout {
CollapsingToolbarLayout.this) - insetTop;
mCollapsingTextHelper.setExpansionFraction(
Math.abs(verticalOffset) / (float) expandRange);
if (Math.abs(verticalOffset) == scrollRange) {
// If we have some pinned children, and we're offset to only show those views,
// we want to be elevate
ViewCompat.setElevation(layout, layout.getTargetElevation());
} else {
// Otherwise, we're inline with the content
ViewCompat.setElevation(layout, 0f);
}
}
}
}

View File

@ -17,7 +17,6 @@
package android.support.design.widget;
import android.os.Build;
import android.view.View;
class ViewUtils {
@ -31,39 +30,6 @@ class ViewUtils {
}
};
private interface ViewUtilsImpl {
void setBoundsViewOutlineProvider(View view);
}
private static class ViewUtilsImplBase implements ViewUtilsImpl {
@Override
public void setBoundsViewOutlineProvider(View view) {
// no-op
}
}
private static class ViewUtilsImplLollipop implements ViewUtilsImpl {
@Override
public void setBoundsViewOutlineProvider(View view) {
ViewUtilsLollipop.setBoundsViewOutlineProvider(view);
}
}
private static final ViewUtilsImpl IMPL;
static {
final int version = Build.VERSION.SDK_INT;
if (version >= 21) {
IMPL = new ViewUtilsImplLollipop();
} else {
IMPL = new ViewUtilsImplBase();
}
}
static void setBoundsViewOutlineProvider(View view) {
IMPL.setBoundsViewOutlineProvider(view);
}
static ValueAnimatorCompat createAnimator() {
return DEFAULT_ANIMATOR_CREATOR.createAnimator();
}

View File

@ -16,6 +16,7 @@
package android.support.design.widget;
import android.os.Build;
import android.support.annotation.CallSuper;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
@ -27,6 +28,7 @@ import android.support.test.espresso.action.CoordinatesProvider;
import android.support.test.espresso.action.GeneralSwipeAction;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Swipe;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
@ -38,6 +40,8 @@ import static android.support.design.testutils.TestUtilsActions.setTitle;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
public abstract class AppBarLayoutBaseTest extends BaseDynamicCoordinatorLayoutTest {
protected AppBarLayout mAppBar;
@ -48,6 +52,8 @@ public abstract class AppBarLayoutBaseTest extends BaseDynamicCoordinatorLayoutT
protected TextView mTextView;
protected float mDefaultElevationValue;
protected static void performVerticalSwipeUpGesture(@IdRes int containerId, final int swipeX,
final int swipeStartY, final int swipeAmountY) {
onView(withId(containerId)).perform(new GeneralSwipeAction(
@ -113,5 +119,14 @@ public abstract class AppBarLayoutBaseTest extends BaseDynamicCoordinatorLayoutT
onView(withId(R.id.textview_dialogue)).perform(
setText(TextUtils.concat(Shakespeare.DIALOGUE)));
}
mDefaultElevationValue = mAppBar.getResources()
.getDimensionPixelSize(R.dimen.design_appbar_elevation);
}
protected void assertAppBarElevation(float expectedValue) {
if (Build.VERSION.SDK_INT >= 21) {
assertEquals(expectedValue, ViewCompat.getElevation(mAppBar), 0.05f);
}
}
}

View File

@ -51,6 +51,8 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
final int longSwipeAmount = 3 * appbarHeight / 2;
final int shortSwipeAmount = toolbarHeight;
assertAppBarElevation(0f);
// Perform a swipe-up gesture across the horizontal center of the screen.
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
@ -74,6 +76,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// At this point the app bar should still be visually snapped below the system status bar
// as it is in the pinned mode. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + toolbarHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-down gesture across the horizontal center of the screen.
// Note that the swipe down is a bit longer than the swipe up to check that the app bar
@ -89,6 +92,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// as it is in the pinned mode and we haven't fully swiped down the content below the
// app bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + toolbarHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -102,6 +106,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(0f);
// Perform yet another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -115,6 +120,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(0f);
}
@Test
@ -141,6 +147,8 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
final int longSwipeAmount = 3 * appbarHeight / 2;
final int shortSwipeAmount = toolbarHeight;
assertAppBarElevation(0f);
// Perform a swipe-up gesture across the horizontal center of the screen.
performVerticalSwipeUpGesture(
R.id.coordinator_layout,
@ -153,6 +161,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// edge aligned with the system status bar.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(0f);
// Perform another swipe-up gesture
performVerticalSwipeUpGesture(
@ -165,6 +174,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// At this point the app bar should still be off the screen. Allow for off-by-a-pixel
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(0f);
// Perform a short swipe-down gesture across the horizontal center of the screen.
// Note that the swipe down is a bit longer than the swipe up to fully bring down
@ -180,6 +190,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// in scrolling mode and we've swiped down, but not fully. Allow for off-by-a-pixel
// margin of error.
assertEquals(originalAppbarTop + toolbarHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -193,6 +204,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1]);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight);
assertAppBarElevation(0f);
// Perform yet another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -206,6 +218,7 @@ public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(0f);
}
@Test

View File

@ -76,6 +76,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the app bar should not be visually "present" on the screen, with its bottom
// edge aligned with the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-up gesture
performVerticalSwipeUpGesture(
@ -88,6 +89,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the app bar should still be off the screen. Allow for off-by-a-pixel
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a long swipe-down gesture across the horizontal center of the screen.
// Note that the swipe down is a bit longer than the swipe up to fully bring down
@ -104,6 +106,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -117,6 +120,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform yet another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -130,6 +134,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
}
@Test
@ -163,6 +168,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the tab bar should be visually snapped below the system status bar.
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-up gesture
performVerticalSwipeUpGesture(
@ -175,6 +181,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the tab bar should still be visually snapped below the system status bar
// as it is in the pinned mode. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-down gesture across the horizontal center of the screen.
// Note that the swipe down is a bit longer than the swipe up to fully bring down
@ -191,6 +198,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -204,6 +212,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform yet another swipe-down gesture across the horizontal center of the screen.
performVerticalSwipeDownGesture(
@ -217,6 +226,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
}
@LargeTest
@ -264,6 +274,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a slightly longer swipe-up gesture, this time by 75% of the toolbar height.
// We expect the snap behavior to move the app bar to snap the tab layout below the
@ -281,6 +292,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the app bar should "snap" the toolbar away and align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-up gesture, this time by 25% of the tab layout height. We expect
// snap behavior to move the app bar back to snap the tab layout below the system status
@ -298,6 +310,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the app bar should "snap" back to align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a longer swipe-up gesture, this time by 75% of the tab layout height. We expect
// snap behavior to move the app bar fully away from the screen.
@ -314,6 +327,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the app bar should not be visually "present" on the screen, with its bottom
// edge aligned with the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-down gesture by 25% of the tab layout height. We expect
// snap behavior to move the app bar back fully away from the screen.
@ -331,6 +345,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// its bottom edge aligned with the system status bar. Allow for off-by-a-pixel margin
// of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a longer swipe-up gesture, this time by 75% of the tab layout height. We expect
// snap behavior to move the app bar to snap the tab layout below the system status
@ -348,6 +363,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the app bar should "snap" the toolbar away and align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a short swipe-down gesture by 25% of the toolbar height. We expect
// snap behavior to align the tab layout below the system status bar
@ -364,6 +380,7 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// At this point the app bar should still align the tab layout below
// the system status bar. Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
// Perform a longer swipe-up gesture, this time by 75% of the toolbar height. We expect
// snap behavior to move the app bar back to its original place (fully visible).
@ -381,5 +398,6 @@ public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
// Allow for off-by-a-pixel margin of error.
assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
assertAppBarElevation(mDefaultElevationValue);
}
}