Home | History | Annotate | Download | only in list
      1 /*
      2  * Copyright (C) 2010 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.android.contacts.common.list;
     18 
     19 import android.content.Context;
     20 import android.util.AttributeSet;
     21 import android.widget.ListView;
     22 
     23 /**
     24  * A ListView that can be asked to scroll (smoothly or otherwise) to a specific
     25  * position.  This class takes advantage of similar functionality that exists
     26  * in {@link ListView} and enhances it.
     27  */
     28 public class AutoScrollListView extends ListView {
     29 
     30     /**
     31      * Position the element at about 1/3 of the list height
     32      */
     33     private static final float PREFERRED_SELECTION_OFFSET_FROM_TOP = 0.33f;
     34 
     35     private int mRequestedScrollPosition = -1;
     36     private boolean mSmoothScrollRequested;
     37 
     38     public AutoScrollListView(Context context) {
     39         super(context);
     40     }
     41 
     42     public AutoScrollListView(Context context, AttributeSet attrs) {
     43         super(context, attrs);
     44     }
     45 
     46     public AutoScrollListView(Context context, AttributeSet attrs, int defStyle) {
     47         super(context, attrs, defStyle);
     48     }
     49 
     50     /**
     51      * Brings the specified position to view by optionally performing a jump-scroll maneuver:
     52      * first it jumps to some position near the one requested and then does a smooth
     53      * scroll to the requested position.  This creates an impression of full smooth
     54      * scrolling without actually traversing the entire list.  If smooth scrolling is
     55      * not requested, instantly positions the requested item at a preferred offset.
     56      */
     57     public void requestPositionToScreen(int position, boolean smoothScroll) {
     58         mRequestedScrollPosition = position;
     59         mSmoothScrollRequested = smoothScroll;
     60         requestLayout();
     61     }
     62 
     63     @Override
     64     protected void layoutChildren() {
     65         super.layoutChildren();
     66         if (mRequestedScrollPosition == -1) {
     67             return;
     68         }
     69 
     70         final int position = mRequestedScrollPosition;
     71         mRequestedScrollPosition = -1;
     72 
     73         int firstPosition = getFirstVisiblePosition() + 1;
     74         int lastPosition = getLastVisiblePosition();
     75         if (position >= firstPosition && position <= lastPosition) {
     76             return; // Already on screen
     77         }
     78 
     79         final int offset = (int) (getHeight() * PREFERRED_SELECTION_OFFSET_FROM_TOP);
     80         if (!mSmoothScrollRequested) {
     81             setSelectionFromTop(position, offset);
     82 
     83             // Since we have changed the scrolling position, we need to redo child layout
     84             // Calling "requestLayout" in the middle of a layout pass has no effect,
     85             // so we call layoutChildren explicitly
     86             super.layoutChildren();
     87 
     88         } else {
     89             // We will first position the list a couple of screens before or after
     90             // the new selection and then scroll smoothly to it.
     91             int twoScreens = (lastPosition - firstPosition) * 2;
     92             int preliminaryPosition;
     93             if (position < firstPosition) {
     94                 preliminaryPosition = position + twoScreens;
     95                 if (preliminaryPosition >= getCount()) {
     96                     preliminaryPosition = getCount() - 1;
     97                 }
     98                 if (preliminaryPosition < firstPosition) {
     99                     setSelection(preliminaryPosition);
    100                     super.layoutChildren();
    101                 }
    102             } else {
    103                 preliminaryPosition = position - twoScreens;
    104                 if (preliminaryPosition < 0) {
    105                     preliminaryPosition = 0;
    106                 }
    107                 if (preliminaryPosition > lastPosition) {
    108                     setSelection(preliminaryPosition);
    109                     super.layoutChildren();
    110                 }
    111             }
    112 
    113 
    114             smoothScrollToPositionFromTop(position, offset);
    115         }
    116     }
    117 }
    118