blob: d0648b70655119894df2ad95f13f5731d6f8c6b2 [file] [log] [blame]
Michael Kolbfe251992010-07-08 15:41:55 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
Michael Kolb27b08392010-10-04 12:49:23 -07004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
Michael Kolbfe251992010-07-08 15:41:55 -07007 *
Michael Kolb27b08392010-10-04 12:49:23 -07008 * http://www.apache.org/licenses/LICENSE-2.0
Michael Kolbfe251992010-07-08 15:41:55 -07009 *
10 * Unless required by applicable law or agreed to in writing, software
Michael Kolb27b08392010-10-04 12:49:23 -070011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
Michael Kolbfe251992010-07-08 15:41:55 -070015 */
16
17package com.android.browser;
18
Michael Kolb27b08392010-10-04 12:49:23 -070019import android.animation.ObjectAnimator;
Michael Kolbfe251992010-07-08 15:41:55 -070020import android.content.Context;
21import android.util.AttributeSet;
22import android.view.View;
23import android.widget.HorizontalScrollView;
24import android.widget.LinearLayout;
25
26/**
27 * custom view for displaying tabs in the tabbed title bar
28 */
29public class TabScrollView extends HorizontalScrollView {
30
Michael Kolbfe251992010-07-08 15:41:55 -070031 private LinearLayout mContentView;
Michael Kolbfe251992010-07-08 15:41:55 -070032 private int mSelected;
Michael Kolb27b08392010-10-04 12:49:23 -070033 private int mAnimationDuration;
Michael Kolb2b5a13a2010-12-09 14:13:42 -080034 private int mTabOverlap;
Michael Kolbfe251992010-07-08 15:41:55 -070035
36 /**
37 * @param context
38 * @param attrs
39 * @param defStyle
40 */
41 public TabScrollView(Context context, AttributeSet attrs, int defStyle) {
42 super(context, attrs, defStyle);
43 init(context);
44 }
45
46 /**
47 * @param context
48 * @param attrs
49 */
50 public TabScrollView(Context context, AttributeSet attrs) {
51 super(context, attrs);
52 init(context);
53 }
54
55 /**
56 * @param context
57 */
58 public TabScrollView(Context context) {
59 super(context);
60 init(context);
61 }
62
63 private void init(Context ctx) {
Michael Kolb27b08392010-10-04 12:49:23 -070064 mAnimationDuration = ctx.getResources().getInteger(
65 R.integer.tab_animation_duration);
Michael Kolb2b5a13a2010-12-09 14:13:42 -080066 mTabOverlap = (int) ctx.getResources().getDimension(R.dimen.tab_overlap);
Michael Kolbfe251992010-07-08 15:41:55 -070067 setHorizontalScrollBarEnabled(false);
Michael Kolb2b5a13a2010-12-09 14:13:42 -080068 setOverScrollMode(OVER_SCROLL_NEVER);
Romain Guye3989562011-01-27 12:06:29 -080069 mContentView = new TabLayout(ctx);
Michael Kolbfe251992010-07-08 15:41:55 -070070 mContentView.setOrientation(LinearLayout.HORIZONTAL);
Michael Kolb27b08392010-10-04 12:49:23 -070071 mContentView.setLayoutParams(
72 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
Michael Kolbf558f0d2011-01-13 19:24:18 -080073 mContentView.setPadding(
74 (int) ctx.getResources().getDimension(R.dimen.tab_first_padding_left),
75 0, 0, 0);
Michael Kolbfe251992010-07-08 15:41:55 -070076 addView(mContentView);
77 mSelected = -1;
Michael Kolb27b08392010-10-04 12:49:23 -070078 // prevent ProGuard from removing the property methods
79 setScroll(getScroll());
Michael Kolbfe251992010-07-08 15:41:55 -070080 }
81
82 @Override
83 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
84 super.onLayout(changed, left, top, right, bottom);
85 ensureChildVisible(getSelectedTab());
86 }
87
88 void setSelectedTab(int position) {
89 View v = getSelectedTab();
90 if (v != null) {
Michael Kolbb7b115e2010-09-25 16:59:37 -070091 v.setActivated(false);
Michael Kolbfe251992010-07-08 15:41:55 -070092 }
93 mSelected = position;
94 v = getSelectedTab();
95 if (v != null) {
Michael Kolbb7b115e2010-09-25 16:59:37 -070096 v.setActivated(true);
Michael Kolbfe251992010-07-08 15:41:55 -070097 }
98 requestLayout();
99 }
100
Michael Kolbebba8b42010-09-30 12:57:59 -0700101 int getChildIndex(View v) {
102 return mContentView.indexOfChild(v);
103 }
104
Michael Kolbfe251992010-07-08 15:41:55 -0700105 View getSelectedTab() {
106 if ((mSelected >= 0) && (mSelected < mContentView.getChildCount())) {
107 return mContentView.getChildAt(mSelected);
108 } else {
109 return null;
110 }
111 }
112
113 void clearTabs() {
114 mContentView.removeAllViews();
115 }
116
117 void addTab(View tab) {
118 mContentView.addView(tab);
Michael Kolbb7b115e2010-09-25 16:59:37 -0700119 tab.setActivated(false);
Michael Kolbfe251992010-07-08 15:41:55 -0700120 }
121
Michael Kolbfe251992010-07-08 15:41:55 -0700122 void removeTab(View tab) {
Michael Kolbbdc2a242010-09-07 13:48:07 -0700123 int ix = mContentView.indexOfChild(tab);
124 if (ix == mSelected) {
125 mSelected = -1;
126 } else if (ix < mSelected) {
127 mSelected--;
128 }
John Reck599e9102011-01-06 20:37:31 -0800129 mContentView.removeView(tab);
Michael Kolbfe251992010-07-08 15:41:55 -0700130 }
131
Michael Kolb27b08392010-10-04 12:49:23 -0700132 private void ensureChildVisible(View child) {
Michael Kolbfe251992010-07-08 15:41:55 -0700133 if (child != null) {
134 int childl = child.getLeft();
135 int childr = childl + child.getWidth();
136 int viewl = getScrollX();
137 int viewr = viewl + getWidth();
138 if (childl < viewl) {
139 // need scrolling to left
Michael Kolb27b08392010-10-04 12:49:23 -0700140 animateScroll(childl);
Michael Kolbfe251992010-07-08 15:41:55 -0700141 } else if (childr > viewr) {
142 // need scrolling to right
Michael Kolb27b08392010-10-04 12:49:23 -0700143 animateScroll(childr - viewr + viewl);
Michael Kolbfe251992010-07-08 15:41:55 -0700144 }
145 }
146 }
147
John Reck599e9102011-01-06 20:37:31 -0800148// TODO: These animations are broken and don't work correctly, removing for now
149// as animateOut is actually causing issues
150// private void animateIn(View tab) {
151// ObjectAnimator animator = ObjectAnimator.ofInt(tab, "TranslationX", 500, 0);
152// animator.setDuration(mAnimationDuration);
153// animator.start();
154// }
155//
156// private void animateOut(final View tab) {
157// ObjectAnimator animator = ObjectAnimator.ofInt(
158// tab, "TranslationX", 0, getScrollX() - tab.getRight());
159// animator.setDuration(mAnimationDuration);
160// animator.addListener(new AnimatorListenerAdapter() {
161// @Override
162// public void onAnimationEnd(Animator animation) {
163// mContentView.removeView(tab);
164// }
165// });
166// animator.setInterpolator(new AccelerateInterpolator());
167// animator.start();
168// }
Michael Kolb27b08392010-10-04 12:49:23 -0700169
170 private void animateScroll(int newscroll) {
Chet Haaseb3a00ab2010-10-14 07:01:46 -0700171 ObjectAnimator animator = ObjectAnimator.ofInt(this, "scroll", getScrollX(), newscroll);
172 animator.setDuration(mAnimationDuration);
Michael Kolb27b08392010-10-04 12:49:23 -0700173 animator.start();
174 }
175
176 /**
177 * required for animation
178 */
179 public void setScroll(int newscroll) {
180 scrollTo(newscroll, getScrollY());
181 }
182
183 /**
184 * required for animation
185 */
186 public int getScroll() {
187 return getScrollX();
188 }
189
Romain Guye3989562011-01-27 12:06:29 -0800190 @Override
191 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
192 super.onScrollChanged(l, t, oldl, oldt);
193
194 // TabViews base their drawing based on their absolute position within the
195 // window. When hardware accelerated, we need to recreate their display list
196 // when they scroll
197 if (isHardwareAccelerated()) {
198 int count = mContentView.getChildCount();
199 for (int i = 0; i < count; i++) {
200 mContentView.getChildAt(i).invalidate();
201 }
202 }
203 }
204
Michael Kolb2b5a13a2010-12-09 14:13:42 -0800205 class TabLayout extends LinearLayout {
206
207 public TabLayout(Context context) {
208 super(context);
209 setChildrenDrawingOrderEnabled(true);
210 }
211
212 @Override
213 protected void onMeasure(int hspec, int vspec) {
214 super.onMeasure(hspec, vspec);
215 int w = getMeasuredWidth();
216 w -= Math.max(0, mContentView.getChildCount() - 1) * mTabOverlap;
217 setMeasuredDimension(w, getMeasuredHeight());
218 }
219
220 @Override
221 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
222 super.onLayout(changed, left, top, right, bottom);
223 if (getChildCount() > 1) {
224 int nextLeft = getChildAt(0).getRight() - mTabOverlap;
225 for (int i = 1; i < getChildCount(); i++) {
226 View tab = getChildAt(i);
227 int w = tab.getRight() - tab.getLeft();
228 tab.layout(nextLeft, tab.getTop(), nextLeft + w, tab.getBottom());
229 nextLeft += w - mTabOverlap;
230 }
231 }
232 }
233
234 @Override
235 protected int getChildDrawingOrder(int count, int i) {
236 int next = -1;
237 if ((i == (count - 1)) && (mSelected >= 0)) {
238 next = mSelected;
239 } else {
240 next = count - i - 1;
241 if (next <= mSelected) {
242 next--;
243 }
244 }
245 return next;
246 }
247
248 }
249
Michael Kolbfe251992010-07-08 15:41:55 -0700250}