@@ -115,6 +115,8 @@ public class CoordinatorLayout extends ViewGroup implements NestedScrollingParen
115
115
NestedScrollingParent3 {
116
116
static final String TAG = "CoordinatorLayout" ;
117
117
static final String WIDGET_PACKAGE_NAME ;
118
+ // For the UP/DOWN keys, we scroll 1/10th of the screen.
119
+ private static final float KEY_SCROLL_FRACTION_AMOUNT = 0.1f ;
118
120
119
121
static {
120
122
final Package pkg = CoordinatorLayout .class .getPackage ();
@@ -181,6 +183,13 @@ private static void releaseTempRect(@NonNull Rect rect) {
181
183
// This only exist to prevent GC and object instantiation costs that are present before API 21.
182
184
private final int [] mNestedScrollingV2ConsumedCompat = new int [2 ];
183
185
186
+ // Array to be mutated by calls to nested scrolling related methods triggered by key events.
187
+ // Because these scrolling events rely on lower level methods using mBehaviorConsumed, we need
188
+ // a separate variable to save memory. As with the above, this only exist to prevent GC and
189
+ // object instantiation costs that are
190
+ // present before API 21.
191
+ private final int [] mKeyTriggeredScrollConsumed = new int [2 ];
192
+
184
193
private boolean mDisallowInterceptReset ;
185
194
186
195
private boolean mIsAttachedToWindow ;
@@ -1945,47 +1954,46 @@ public boolean dispatchKeyEvent(
1945
1954
if (event .getAction () == KeyEvent .ACTION_DOWN ) {
1946
1955
switch (event .getKeyCode ()) {
1947
1956
case KeyEvent .KEYCODE_DPAD_UP :
1948
- case KeyEvent .KEYCODE_DPAD_DOWN :
1949
- case KeyEvent .KEYCODE_SPACE :
1950
-
1951
- int yScrollDelta ;
1952
-
1953
- if (event .getKeyCode () == KeyEvent .KEYCODE_SPACE ) {
1954
- if (event .isShiftPressed ()) {
1955
- // Places the CoordinatorLayout at the top of the available
1956
- // content.
1957
- // Note: The delta may represent a value that would overshoot the
1958
- // top of the screen, but the children only use as much of the
1959
- // delta as they can support, so it will always go exactly to the
1960
- // top.
1961
- yScrollDelta = -getFullContentHeight ();
1962
- } else {
1963
- // Places the CoordinatorLayout at the bottom of the available
1964
- // content.
1965
- yScrollDelta = getFullContentHeight () - getHeight ();
1966
- }
1967
-
1968
- } else if (event .isAltPressed ()) { // For UP and DOWN KeyEvents
1969
- // Full page scroll
1970
- yScrollDelta = getHeight ();
1957
+ if (event .isAltPressed ()) {
1958
+ // Inverse to move up the screen
1959
+ handled = moveVertically (-pageDelta ());
1960
+ } else {
1961
+ // Inverse to move up the screen
1962
+ handled = moveVertically (-lineDelta ());
1963
+ }
1964
+ break ;
1971
1965
1966
+ case KeyEvent .KEYCODE_DPAD_DOWN :
1967
+ if (event .isAltPressed ()) {
1968
+ handled = moveVertically (pageDelta ());
1972
1969
} else {
1973
- // Regular arrow scroll
1974
- yScrollDelta = (int ) (getHeight () * 0.1f );
1970
+ handled = moveVertically (lineDelta ());
1975
1971
}
1972
+ break ;
1973
+
1974
+ case KeyEvent .KEYCODE_PAGE_UP :
1975
+ // Inverse to move up the screen
1976
+ handled = moveVertically (-pageDelta ());
1977
+ break ;
1976
1978
1977
- View focusedView = findDeepestFocusedChild (this );
1979
+ case KeyEvent .KEYCODE_PAGE_DOWN :
1980
+ handled = moveVertically (pageDelta ());
1981
+ break ;
1978
1982
1979
- // Convert delta to negative if the key event is UP.
1980
- if (event .getKeyCode () == KeyEvent .KEYCODE_DPAD_UP ) {
1981
- yScrollDelta = -yScrollDelta ;
1983
+ case KeyEvent .KEYCODE_SPACE :
1984
+ if (event .isShiftPressed ()) {
1985
+ handled = moveVertically (distanceToTop ());
1986
+ } else {
1987
+ handled = moveVertically (distanceToBottom ());
1982
1988
}
1989
+ break ;
1983
1990
1984
- handled = manuallyTriggersNestedScrollFromKeyEvent (
1985
- focusedView ,
1986
- yScrollDelta
1987
- );
1991
+ case KeyEvent .KEYCODE_MOVE_HOME :
1992
+ handled = moveVertically (distanceToTop ());
1993
+ break ;
1988
1994
1995
+ case KeyEvent .KEYCODE_MOVE_END :
1996
+ handled = moveVertically (distanceToBottom ());
1989
1997
break ;
1990
1998
}
1991
1999
}
@@ -1994,6 +2002,36 @@ public boolean dispatchKeyEvent(
1994
2002
return handled ;
1995
2003
}
1996
2004
2005
+ // Distance for moving one arrow key tap.
2006
+ private int lineDelta () {
2007
+ return (int ) (getHeight () * KEY_SCROLL_FRACTION_AMOUNT );
2008
+ }
2009
+
2010
+ private int pageDelta () {
2011
+ return getHeight ();
2012
+ }
2013
+
2014
+ private int distanceToTop () {
2015
+ // Note: The delta may represent a value that would overshoot the
2016
+ // top of the screen, but the children only use as much of the
2017
+ // delta as they can support, so it will always go exactly to the
2018
+ // top.
2019
+ return -getFullContentHeight ();
2020
+ }
2021
+
2022
+ private int distanceToBottom () {
2023
+ return getFullContentHeight () - getHeight ();
2024
+ }
2025
+
2026
+ private boolean moveVertically (int yScrollDelta ) {
2027
+ View focusedView = findDeepestFocusedChild (this );
2028
+
2029
+ return manuallyTriggersNestedScrollFromKeyEvent (
2030
+ focusedView ,
2031
+ yScrollDelta
2032
+ );
2033
+ }
2034
+
1997
2035
private View findDeepestFocusedChild (View startingParentView ) {
1998
2036
View focusedView = startingParentView ;
1999
2037
while (focusedView != null ) {
@@ -2050,19 +2088,23 @@ private boolean manuallyTriggersNestedScrollFromKeyEvent(View focusedView, int y
2050
2088
ViewCompat .TYPE_NON_TOUCH
2051
2089
);
2052
2090
2091
+ // Reset consumed values to zero.
2092
+ mKeyTriggeredScrollConsumed [0 ] = 0 ;
2093
+ mKeyTriggeredScrollConsumed [1 ] = 0 ;
2094
+
2053
2095
onNestedScroll (
2054
2096
focusedView ,
2055
2097
0 ,
2056
2098
0 ,
2057
2099
0 ,
2058
2100
yScrollDelta ,
2059
2101
ViewCompat .TYPE_NON_TOUCH ,
2060
- mBehaviorConsumed
2102
+ mKeyTriggeredScrollConsumed
2061
2103
);
2062
2104
2063
2105
onStopNestedScroll (focusedView , ViewCompat .TYPE_NON_TOUCH );
2064
2106
2065
- if (mBehaviorConsumed [1 ] > 0 ) {
2107
+ if (mKeyTriggeredScrollConsumed [1 ] > 0 ) {
2066
2108
handled = true ;
2067
2109
}
2068
2110
0 commit comments