@@ -3985,7 +3985,7 @@ public void run() {
39853985 }
39863986
39873987 class PositionScroller implements Runnable {
3988- private static final int SCROLL_DURATION = 400 ;
3988+ private static final int SCROLL_DURATION = 200 ;
39893989
39903990 private static final int MOVE_DOWN_POS = 1 ;
39913991 private static final int MOVE_UP_POS = 2 ;
@@ -4006,21 +4006,35 @@ class PositionScroller implements Runnable {
40064006 mExtraScroll = ViewConfiguration .get (mContext ).getScaledFadingEdgeLength ();
40074007 }
40084008
4009- void start (int position ) {
4009+ void start (final int position ) {
40104010 stop ();
40114011
4012+ final int childCount = getChildCount ();
4013+ if (childCount == 0 ) {
4014+ // Can't scroll without children.
4015+ if (mDataChanged ) {
4016+ // But we might have something in a minute.
4017+ post (new Runnable () {
4018+ @ Override public void run () {
4019+ start (position );
4020+ }
4021+ });
4022+ }
4023+ return ;
4024+ }
4025+
40124026 final int firstPos = mFirstPosition ;
4013- final int lastPos = firstPos + getChildCount () - 1 ;
4027+ final int lastPos = firstPos + childCount - 1 ;
40144028
40154029 int viewTravelCount ;
4016- if (position <= firstPos ) {
4030+ if (position < firstPos ) {
40174031 viewTravelCount = firstPos - position + 1 ;
40184032 mMode = MOVE_UP_POS ;
4019- } else if (position >= lastPos ) {
4033+ } else if (position > lastPos ) {
40204034 viewTravelCount = position - lastPos + 1 ;
40214035 mMode = MOVE_DOWN_POS ;
40224036 } else {
4023- // Already on screen, nothing to do
4037+ scrollToVisible ( position , INVALID_POSITION , SCROLL_DURATION );
40244038 return ;
40254039 }
40264040
@@ -4036,19 +4050,33 @@ void start(int position) {
40364050 postOnAnimation (this );
40374051 }
40384052
4039- void start (int position , int boundPosition ) {
4053+ void start (final int position , final int boundPosition ) {
40404054 stop ();
40414055
40424056 if (boundPosition == INVALID_POSITION ) {
40434057 start (position );
40444058 return ;
40454059 }
40464060
4061+ final int childCount = getChildCount ();
4062+ if (childCount == 0 ) {
4063+ // Can't scroll without children.
4064+ if (mDataChanged ) {
4065+ // But we might have something in a minute.
4066+ post (new Runnable () {
4067+ @ Override public void run () {
4068+ start (position , boundPosition );
4069+ }
4070+ });
4071+ }
4072+ return ;
4073+ }
4074+
40474075 final int firstPos = mFirstPosition ;
4048- final int lastPos = firstPos + getChildCount () - 1 ;
4076+ final int lastPos = firstPos + childCount - 1 ;
40494077
40504078 int viewTravelCount ;
4051- if (position <= firstPos ) {
4079+ if (position < firstPos ) {
40524080 final int boundPosFromLast = lastPos - boundPosition ;
40534081 if (boundPosFromLast < 1 ) {
40544082 // Moving would shift our bound position off the screen. Abort.
@@ -4064,7 +4092,7 @@ void start(int position, int boundPosition) {
40644092 viewTravelCount = posTravel ;
40654093 mMode = MOVE_UP_POS ;
40664094 }
4067- } else if (position >= lastPos ) {
4095+ } else if (position > lastPos ) {
40684096 final int boundPosFromFirst = boundPosition - firstPos ;
40694097 if (boundPosFromFirst < 1 ) {
40704098 // Moving would shift our bound position off the screen. Abort.
@@ -4081,7 +4109,7 @@ void start(int position, int boundPosition) {
40814109 mMode = MOVE_DOWN_POS ;
40824110 }
40834111 } else {
4084- // Already on screen, nothing to do
4112+ scrollToVisible ( position , boundPosition , SCROLL_DURATION );
40854113 return ;
40864114 }
40874115
@@ -4137,6 +4165,60 @@ void startWithOffset(int position, int offset, int duration) {
41374165 postOnAnimation (this );
41384166 }
41394167
4168+ /**
4169+ * Scroll such that targetPos is in the visible padded region without scrolling
4170+ * boundPos out of view. Assumes targetPos is onscreen.
4171+ */
4172+ void scrollToVisible (int targetPos , int boundPos , int duration ) {
4173+ final int firstPos = mFirstPosition ;
4174+ final int childCount = getChildCount ();
4175+ final int lastPos = firstPos + childCount - 1 ;
4176+ final int paddedTop = mListPadding .top ;
4177+ final int paddedBottom = getHeight () - mListPadding .bottom ;
4178+
4179+ if (targetPos < firstPos || targetPos > lastPos ) {
4180+ Log .w (TAG , "scrollToVisible called with targetPos " + targetPos +
4181+ " not visible [" + firstPos + ", " + lastPos + "]" );
4182+ }
4183+ if (boundPos < firstPos || boundPos > lastPos ) {
4184+ // boundPos doesn't matter, it's already offscreen.
4185+ boundPos = INVALID_POSITION ;
4186+ }
4187+
4188+ final View targetChild = getChildAt (targetPos - firstPos );
4189+ final int targetTop = targetChild .getTop ();
4190+ final int targetBottom = targetChild .getBottom ();
4191+ int scrollBy = 0 ;
4192+
4193+ if (targetBottom > paddedBottom ) {
4194+ scrollBy = targetBottom - paddedBottom ;
4195+ }
4196+ if (targetTop < paddedTop ) {
4197+ scrollBy = targetTop - paddedTop ;
4198+ }
4199+
4200+ if (scrollBy == 0 ) {
4201+ return ;
4202+ }
4203+
4204+ if (boundPos >= 0 ) {
4205+ final View boundChild = getChildAt (boundPos - firstPos );
4206+ final int boundTop = boundChild .getTop ();
4207+ final int boundBottom = boundChild .getBottom ();
4208+ final int absScroll = Math .abs (scrollBy );
4209+
4210+ if (scrollBy < 0 && boundBottom + absScroll > paddedBottom ) {
4211+ // Don't scroll the bound view off the bottom of the screen.
4212+ scrollBy = Math .max (0 , boundBottom - paddedBottom );
4213+ } else if (scrollBy > 0 && boundTop - absScroll < paddedTop ) {
4214+ // Don't scroll the bound view off the top of the screen.
4215+ scrollBy = Math .min (0 , boundTop - paddedTop );
4216+ }
4217+ }
4218+
4219+ smoothScrollBy (scrollBy , duration );
4220+ }
4221+
41404222 void stop () {
41414223 removeCallbacks (this );
41424224 }
0 commit comments