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