blob: 04ed5a3c099086e9649e66a16f2140e86112ece0 [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.Animator;
Chet Haaseb3a00ab2010-10-14 07:01:46 -070020import android.animation.AnimatorListenerAdapter;
Michael Kolb27b08392010-10-04 12:49:23 -070021import android.animation.ObjectAnimator;
Michael Kolbfe251992010-07-08 15:41:55 -070022import android.content.Context;
Michael Kolbc3503762010-10-03 14:45:11 -070023import android.graphics.Canvas;
24import android.graphics.drawable.Drawable;
Michael Kolbfe251992010-07-08 15:41:55 -070025import android.util.AttributeSet;
26import android.view.View;
Michael Kolb27b08392010-10-04 12:49:23 -070027import android.view.animation.AccelerateInterpolator;
Michael Kolbfe251992010-07-08 15:41:55 -070028import android.widget.HorizontalScrollView;
29import android.widget.LinearLayout;
30
31/**
32 * custom view for displaying tabs in the tabbed title bar
33 */
34public class TabScrollView extends HorizontalScrollView {
35
Michael Kolb8233fac2010-10-26 16:08:53 -070036 private Context mContext;
Michael Kolbfe251992010-07-08 15:41:55 -070037 private LinearLayout mContentView;
Michael Kolbfe251992010-07-08 15:41:55 -070038 private int mSelected;
Michael Kolbc3503762010-10-03 14:45:11 -070039 private Drawable mArrowLeft;
40 private Drawable mArrowRight;
Michael Kolb27b08392010-10-04 12:49:23 -070041 private int mAnimationDuration;
Michael Kolb2b5a13a2010-12-09 14:13:42 -080042 private int mTabOverlap;
Michael Kolbfe251992010-07-08 15:41:55 -070043
44 /**
45 * @param context
46 * @param attrs
47 * @param defStyle
48 */
49 public TabScrollView(Context context, AttributeSet attrs, int defStyle) {
50 super(context, attrs, defStyle);
51 init(context);
52 }
53
54 /**
55 * @param context
56 * @param attrs
57 */
58 public TabScrollView(Context context, AttributeSet attrs) {
59 super(context, attrs);
60 init(context);
61 }
62
63 /**
64 * @param context
65 */
66 public TabScrollView(Context context) {
67 super(context);
68 init(context);
69 }
70
71 private void init(Context ctx) {
Michael Kolb8233fac2010-10-26 16:08:53 -070072 mContext = ctx;
Michael Kolb27b08392010-10-04 12:49:23 -070073 mAnimationDuration = ctx.getResources().getInteger(
74 R.integer.tab_animation_duration);
Michael Kolb2b5a13a2010-12-09 14:13:42 -080075 mTabOverlap = (int) ctx.getResources().getDimension(R.dimen.tab_overlap);
Michael Kolbfe251992010-07-08 15:41:55 -070076 setHorizontalScrollBarEnabled(false);
Michael Kolb2b5a13a2010-12-09 14:13:42 -080077 setOverScrollMode(OVER_SCROLL_NEVER);
78 mContentView = new TabLayout(mContext);
Michael Kolbfe251992010-07-08 15:41:55 -070079 mContentView.setOrientation(LinearLayout.HORIZONTAL);
Michael Kolb27b08392010-10-04 12:49:23 -070080 mContentView.setLayoutParams(
81 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
Michael Kolbfe251992010-07-08 15:41:55 -070082 addView(mContentView);
83 mSelected = -1;
Michael Kolbc3503762010-10-03 14:45:11 -070084 mArrowLeft = ctx.getResources().getDrawable(R.drawable.ic_arrow_left);
85 mArrowRight = ctx.getResources().getDrawable(R.drawable.ic_arrow_right);
Michael Kolb27b08392010-10-04 12:49:23 -070086 // prevent ProGuard from removing the property methods
87 setScroll(getScroll());
Michael Kolbfe251992010-07-08 15:41:55 -070088 }
89
90 @Override
91 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
92 super.onLayout(changed, left, top, right, bottom);
93 ensureChildVisible(getSelectedTab());
94 }
95
96 void setSelectedTab(int position) {
97 View v = getSelectedTab();
98 if (v != null) {
Michael Kolbb7b115e2010-09-25 16:59:37 -070099 v.setActivated(false);
Michael Kolbfe251992010-07-08 15:41:55 -0700100 }
101 mSelected = position;
102 v = getSelectedTab();
103 if (v != null) {
Michael Kolbb7b115e2010-09-25 16:59:37 -0700104 v.setActivated(true);
Michael Kolbfe251992010-07-08 15:41:55 -0700105 }
106 requestLayout();
107 }
108
Michael Kolbebba8b42010-09-30 12:57:59 -0700109 int getChildIndex(View v) {
110 return mContentView.indexOfChild(v);
111 }
112
Michael Kolbfe251992010-07-08 15:41:55 -0700113 View getSelectedTab() {
114 if ((mSelected >= 0) && (mSelected < mContentView.getChildCount())) {
115 return mContentView.getChildAt(mSelected);
116 } else {
117 return null;
118 }
119 }
120
121 void clearTabs() {
122 mContentView.removeAllViews();
123 }
124
125 void addTab(View tab) {
126 mContentView.addView(tab);
Michael Kolb27b08392010-10-04 12:49:23 -0700127 animateIn(tab);
Michael Kolbb7b115e2010-09-25 16:59:37 -0700128 tab.setActivated(false);
Michael Kolbfe251992010-07-08 15:41:55 -0700129 }
130
Michael Kolbfe251992010-07-08 15:41:55 -0700131 void removeTab(View tab) {
Michael Kolbbdc2a242010-09-07 13:48:07 -0700132 int ix = mContentView.indexOfChild(tab);
133 if (ix == mSelected) {
134 mSelected = -1;
135 } else if (ix < mSelected) {
136 mSelected--;
137 }
Michael Kolb27b08392010-10-04 12:49:23 -0700138 animateOut(tab);
Michael Kolbfe251992010-07-08 15:41:55 -0700139 }
140
Michael Kolb27b08392010-10-04 12:49:23 -0700141 private void ensureChildVisible(View child) {
Michael Kolbfe251992010-07-08 15:41:55 -0700142 if (child != null) {
143 int childl = child.getLeft();
144 int childr = childl + child.getWidth();
145 int viewl = getScrollX();
146 int viewr = viewl + getWidth();
147 if (childl < viewl) {
148 // need scrolling to left
Michael Kolb27b08392010-10-04 12:49:23 -0700149 animateScroll(childl);
Michael Kolbfe251992010-07-08 15:41:55 -0700150 } else if (childr > viewr) {
151 // need scrolling to right
Michael Kolb27b08392010-10-04 12:49:23 -0700152 animateScroll(childr - viewr + viewl);
Michael Kolbfe251992010-07-08 15:41:55 -0700153 }
154 }
155 }
156
Michael Kolbc3503762010-10-03 14:45:11 -0700157 @Override
158 protected void dispatchDraw(Canvas canvas) {
159 super.dispatchDraw(canvas);
160 int l = getScrollX();
161 int r = l + getWidth();
162 int dis = 8;
163 if (l > 0) {
164 int aw = mArrowLeft.getIntrinsicWidth();
165 mArrowLeft.setBounds(l + dis, 0, l + dis + aw, getHeight());
166 mArrowLeft.draw(canvas);
167 }
168 if (r < mContentView.getWidth()) {
169 int aw = mArrowRight.getIntrinsicWidth();
170 mArrowRight.setBounds(r - dis - aw, 0, r - dis, getHeight());
171 mArrowRight.draw(canvas);
172 }
173 }
174
Michael Kolb27b08392010-10-04 12:49:23 -0700175 private void animateIn(View tab) {
Chet Haaseb3a00ab2010-10-14 07:01:46 -0700176 ObjectAnimator animator = ObjectAnimator.ofInt(tab, "TranslationX", 500, 0);
177 animator.setDuration(mAnimationDuration);
Michael Kolb27b08392010-10-04 12:49:23 -0700178 animator.start();
179 }
180
181 private void animateOut(final View tab) {
Chet Haaseb3a00ab2010-10-14 07:01:46 -0700182 ObjectAnimator animator = ObjectAnimator.ofInt(
183 tab, "TranslationX", 0, getScrollX() - tab.getRight());
184 animator.setDuration(mAnimationDuration);
185 animator.addListener(new AnimatorListenerAdapter() {
Michael Kolb27b08392010-10-04 12:49:23 -0700186 @Override
187 public void onAnimationEnd(Animator animation) {
188 mContentView.removeView(tab);
189 }
Michael Kolb27b08392010-10-04 12:49:23 -0700190 });
191 animator.setInterpolator(new AccelerateInterpolator());
192 animator.start();
193 }
194
195 private void animateScroll(int newscroll) {
Chet Haaseb3a00ab2010-10-14 07:01:46 -0700196 ObjectAnimator animator = ObjectAnimator.ofInt(this, "scroll", getScrollX(), newscroll);
197 animator.setDuration(mAnimationDuration);
Michael Kolb27b08392010-10-04 12:49:23 -0700198 animator.start();
199 }
200
201 /**
202 * required for animation
203 */
204 public void setScroll(int newscroll) {
205 scrollTo(newscroll, getScrollY());
206 }
207
208 /**
209 * required for animation
210 */
211 public int getScroll() {
212 return getScrollX();
213 }
214
Michael Kolb2b5a13a2010-12-09 14:13:42 -0800215 class TabLayout extends LinearLayout {
216
217 public TabLayout(Context context) {
218 super(context);
219 setChildrenDrawingOrderEnabled(true);
220 }
221
222 @Override
223 protected void onMeasure(int hspec, int vspec) {
224 super.onMeasure(hspec, vspec);
225 int w = getMeasuredWidth();
226 w -= Math.max(0, mContentView.getChildCount() - 1) * mTabOverlap;
227 setMeasuredDimension(w, getMeasuredHeight());
228 }
229
230 @Override
231 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
232 super.onLayout(changed, left, top, right, bottom);
233 if (getChildCount() > 1) {
234 int nextLeft = getChildAt(0).getRight() - mTabOverlap;
235 for (int i = 1; i < getChildCount(); i++) {
236 View tab = getChildAt(i);
237 int w = tab.getRight() - tab.getLeft();
238 tab.layout(nextLeft, tab.getTop(), nextLeft + w, tab.getBottom());
239 nextLeft += w - mTabOverlap;
240 }
241 }
242 }
243
244 @Override
245 protected int getChildDrawingOrder(int count, int i) {
246 int next = -1;
247 if ((i == (count - 1)) && (mSelected >= 0)) {
248 next = mSelected;
249 } else {
250 next = count - i - 1;
251 if (next <= mSelected) {
252 next--;
253 }
254 }
255 return next;
256 }
257
258 }
259
Michael Kolbfe251992010-07-08 15:41:55 -0700260}