Skip to content

Commit 10ac255

Browse files
drchenhunterstich
authored andcommitted
Automated g4 rollback of changelist 457744460
PiperOrigin-RevId: 459744654
1 parent 2719859 commit 10ac255

File tree

3 files changed

+293
-0
lines changed

3 files changed

+293
-0
lines changed

lib/java/com/google/android/material/appbar/AppBarLayout.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,10 @@ public final int getTotalScrollRange() {
677677
int range = 0;
678678
for (int i = 0, z = getChildCount(); i < z; i++) {
679679
final View child = getChildAt(i);
680+
if (child.getVisibility() == GONE) {
681+
// Gone views should not be included in the scroll range calculation.
682+
continue;
683+
}
680684
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
681685
final int childHeight = child.getMeasuredHeight();
682686
final int flags = lp.scrollFlags;
@@ -725,6 +729,10 @@ int getDownNestedPreScrollRange() {
725729
int range = 0;
726730
for (int i = getChildCount() - 1; i >= 0; i--) {
727731
final View child = getChildAt(i);
732+
if (child.getVisibility() == GONE) {
733+
// Gone views should not be included in the scroll range calculation.
734+
continue;
735+
}
728736
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
729737
final int childHeight = child.getMeasuredHeight();
730738
final int flags = lp.scrollFlags;
@@ -768,6 +776,10 @@ int getDownNestedScrollRange() {
768776
int range = 0;
769777
for (int i = 0, z = getChildCount(); i < z; i++) {
770778
final View child = getChildAt(i);
779+
if (child.getVisibility() == GONE) {
780+
// Gone views should not be included in the scroll range calculation.
781+
continue;
782+
}
771783
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
772784
int childHeight = child.getMeasuredHeight();
773785
childHeight += lp.topMargin + lp.bottomMargin;
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/*
2+
* Copyright (C) 2022 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.android.material.appbar;
18+
19+
import com.google.android.material.test.R;
20+
21+
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
22+
import static com.google.common.truth.Truth.assertThat;
23+
24+
import android.os.Bundle;
25+
import androidx.appcompat.app.AppCompatActivity;
26+
import android.view.View;
27+
import androidx.core.view.ViewCompat;
28+
import com.google.android.material.appbar.AppBarLayout.LayoutParams;
29+
import org.junit.Before;
30+
import org.junit.Test;
31+
import org.junit.runner.RunWith;
32+
import org.robolectric.Robolectric;
33+
import org.robolectric.RobolectricTestRunner;
34+
35+
@RunWith(RobolectricTestRunner.class)
36+
public class AppBarLayoutTest {
37+
38+
private AppBarLayout appBarLayout;
39+
private View firstScrollableChild;
40+
private View secondScrollableChild;
41+
42+
@Before
43+
public void setUp() {
44+
AppCompatActivity activity = Robolectric.buildActivity(TestActivity.class).setup().get();
45+
appBarLayout =
46+
(AppBarLayout) activity.getLayoutInflater().inflate(R.layout.test_appbarlayout, null);
47+
firstScrollableChild = appBarLayout.findViewById(R.id.firstScrollableChild);
48+
secondScrollableChild = appBarLayout.findViewById(R.id.secondScrollableChild);
49+
50+
activity.setContentView(appBarLayout);
51+
52+
// Wait until the layout is measured.
53+
getInstrumentation().waitForIdleSync();
54+
}
55+
56+
@Test
57+
public void testTotalScrollRange_whenFirstChildScrollableAndVisible_onlyCountFirstChild() {
58+
assertThat(appBarLayout.getTotalScrollRange())
59+
.isEqualTo(getChildScrollRange(firstScrollableChild));
60+
}
61+
62+
@Test
63+
public void testTotalScrollRange_whenFirstChildNotExitUntilCollapsed_countFirstTwoChildren() {
64+
// Total scroll range will include all children until the first exit-until-collapsed child
65+
setExitUntilCollapsed(firstScrollableChild, false);
66+
67+
assertThat(appBarLayout.getTotalScrollRange())
68+
.isEqualTo(
69+
getChildScrollRange(firstScrollableChild) + getChildScrollRange(secondScrollableChild));
70+
}
71+
72+
@Test
73+
public void testTotalScrollRange_whenFirstChildGone_onlyCountSecondChild() {
74+
firstScrollableChild.setVisibility(View.GONE);
75+
76+
assertThat(appBarLayout.getTotalScrollRange())
77+
.isEqualTo(getChildScrollRange(secondScrollableChild));
78+
}
79+
80+
@Test
81+
public void testTotalScrollRange_noVisibleScrollableChild_returnZero() {
82+
firstScrollableChild.setVisibility(View.GONE);
83+
secondScrollableChild.setVisibility(View.GONE);
84+
85+
assertThat(appBarLayout.getTotalScrollRange()).isEqualTo(0);
86+
}
87+
88+
@Test
89+
public void testTotalScrollRange_whenFirstChildNotScrollable_returnZero() {
90+
appBarLayout.removeView(firstScrollableChild);
91+
appBarLayout.removeView(secondScrollableChild);
92+
appBarLayout.addView(firstScrollableChild);
93+
94+
assertThat(appBarLayout.getTotalScrollRange()).isEqualTo(0);
95+
}
96+
97+
@Test
98+
public void testDownNestedPreScrollRange_noEnterAlwaysChild_returnZero() {
99+
assertThat(appBarLayout.getDownNestedPreScrollRange()).isEqualTo(0);
100+
}
101+
102+
@Test
103+
public void testDownNestedPreScrollRange_whenFirstChildEnterAlways_onlyCountFirstChild() {
104+
setEnterAlways(firstScrollableChild, true);
105+
106+
assertThat(appBarLayout.getDownNestedPreScrollRange())
107+
.isEqualTo(getChildDownNestedPreScrollRange(firstScrollableChild));
108+
}
109+
110+
@Test
111+
public void testDownNestedPreScrollRange_whenFirstChildEnterAlwaysButGone_returnZero() {
112+
setEnterAlways(firstScrollableChild, true);
113+
firstScrollableChild.setVisibility(View.GONE);
114+
115+
assertThat(appBarLayout.getDownNestedPreScrollRange()).isEqualTo(0);
116+
}
117+
118+
@Test
119+
public void testDownNestedPreScrollRange_whenFirstChildGone_onlyCountSecondChild() {
120+
setEnterAlways(firstScrollableChild, true);
121+
firstScrollableChild.setVisibility(View.GONE);
122+
setEnterAlways(secondScrollableChild, true);
123+
124+
assertThat(appBarLayout.getDownNestedPreScrollRange())
125+
.isEqualTo(getChildDownNestedPreScrollRange(secondScrollableChild));
126+
}
127+
128+
@Test
129+
public void
130+
testDownNestedPreScrollRange_whenFirstChildEnterAlwaysCollapsed_onlyCountFirstChild() {
131+
setEnterAlways(firstScrollableChild, true);
132+
setEnterAlwaysCollapsed(firstScrollableChild, true);
133+
134+
assertThat(appBarLayout.getDownNestedPreScrollRange())
135+
.isEqualTo(getChildDownNestedPreScrollRange(firstScrollableChild));
136+
}
137+
138+
@Test
139+
public void testDownNestedScrollRange_whenFirstChildScrollableAndVisible_onlyCountFirstChild() {
140+
assertThat(appBarLayout.getDownNestedScrollRange())
141+
.isEqualTo(getChildDownNestedScrollRange(firstScrollableChild));
142+
}
143+
144+
@Test
145+
public void testDownNestedRange_whenFirstChildNotExitUntilCollapsed_countFirstTwoChildren() {
146+
// Down nested scroll range will include all children until the first exit-until-collapsed child
147+
setExitUntilCollapsed(firstScrollableChild, false);
148+
149+
assertThat(appBarLayout.getDownNestedScrollRange())
150+
.isEqualTo(
151+
getChildDownNestedScrollRange(firstScrollableChild)
152+
+ getChildDownNestedScrollRange(secondScrollableChild));
153+
}
154+
155+
@Test
156+
public void testDownNestedScrollRange_whenFirstChildGone_onlyCountSecondChild() {
157+
firstScrollableChild.setVisibility(View.GONE);
158+
159+
assertThat(appBarLayout.getDownNestedScrollRange())
160+
.isEqualTo(getChildDownNestedScrollRange(secondScrollableChild));
161+
}
162+
163+
@Test
164+
public void testDownNestedScrollRange_noVisibleScrollableChild_returnZero() {
165+
firstScrollableChild.setVisibility(View.GONE);
166+
secondScrollableChild.setVisibility(View.GONE);
167+
168+
assertThat(appBarLayout.getDownNestedScrollRange()).isEqualTo(0);
169+
}
170+
171+
@Test
172+
public void testDownNestedScrollRange_whenFirstChildNotScrollable_returnZero() {
173+
appBarLayout.removeView(firstScrollableChild);
174+
appBarLayout.removeView(secondScrollableChild);
175+
appBarLayout.addView(firstScrollableChild);
176+
177+
assertThat(appBarLayout.getDownNestedScrollRange()).isEqualTo(0);
178+
}
179+
180+
private static int getChildScrollRange(View child) {
181+
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
182+
return getChildFullHeight(child, lp)
183+
- (isExitUntilCollapsed(lp) ? ViewCompat.getMinimumHeight(child) : 0);
184+
}
185+
186+
private static int getChildDownNestedPreScrollRange(View child) {
187+
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
188+
if (isEnterAlwaysCollapsed(lp)) {
189+
return ViewCompat.getMinimumHeight(child) + lp.topMargin + lp.bottomMargin;
190+
}
191+
return getChildScrollRange(child);
192+
}
193+
194+
private static int getChildDownNestedScrollRange(View child) {
195+
return getChildScrollRange(child);
196+
}
197+
198+
private static int getChildFullHeight(View child, LayoutParams lp) {
199+
return child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
200+
}
201+
202+
private static void setExitUntilCollapsed(View child, boolean exitUntilCollapsed) {
203+
enableFlag(child, LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED, exitUntilCollapsed);
204+
}
205+
206+
private static void setEnterAlwaysCollapsed(View child, boolean enterAlwaysCollapsed) {
207+
enableFlag(child, LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED, enterAlwaysCollapsed);
208+
}
209+
210+
private static void setEnterAlways(View child, boolean enterAlways) {
211+
enableFlag(child, LayoutParams.SCROLL_FLAG_ENTER_ALWAYS, enterAlways);
212+
}
213+
214+
private static void enableFlag(View child, int flag, boolean enable) {
215+
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
216+
if (enable) {
217+
lp.scrollFlags = lp.scrollFlags | flag;
218+
} else {
219+
lp.scrollFlags = lp.scrollFlags & ~flag;
220+
}
221+
}
222+
223+
private static boolean isExitUntilCollapsed(LayoutParams lp) {
224+
return (lp.scrollFlags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0;
225+
}
226+
227+
private static boolean isEnterAlwaysCollapsed(LayoutParams lp) {
228+
return (lp.scrollFlags & LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED) != 0;
229+
}
230+
231+
private static class TestActivity extends AppCompatActivity {
232+
@Override
233+
protected void onCreate(Bundle bundle) {
234+
super.onCreate(bundle);
235+
setTheme(R.style.Theme_Material3_Light_NoActionBar);
236+
}
237+
}
238+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Copyright (C) 2022 The Android Open Source Project
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<com.google.android.material.appbar.AppBarLayout
18+
xmlns:android="http://schemas.android.com/apk/res/android"
19+
xmlns:app="http://schemas.android.com/apk/res-auto"
20+
android:layout_width="match_parent"
21+
android:layout_height="wrap_content">
22+
23+
<View
24+
android:id="@+id/firstScrollableChild"
25+
android:layout_width="match_parent"
26+
android:layout_height="200dp"
27+
android:layout_marginTop="10dp"
28+
android:layout_marginBottom="15dp"
29+
app:layout_scrollFlags="scroll|exitUntilCollapsed" />
30+
31+
<View
32+
android:id="@+id/secondScrollableChild"
33+
android:layout_width="match_parent"
34+
android:layout_height="100dp"
35+
android:minHeight="50dp"
36+
app:layout_scrollFlags="scroll|exitUntilCollapsed" />
37+
38+
<View
39+
android:id="@+id/fixedChild"
40+
android:layout_width="match_parent"
41+
android:layout_height="150dp" />
42+
43+
</com.google.android.material.appbar.AppBarLayout>

0 commit comments

Comments
 (0)