blob: bd26df7049805a302a6974b0bf91803540ffc496 [file] [log] [blame]
Michael Kolb2814a362011-05-19 15:49:41 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * 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
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, 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.
15 */
16
17package com.android.browser;
18
Michael Kolb2814a362011-05-19 15:49:41 -070019import android.content.Context;
Michael Kolb4bd767d2011-05-27 11:33:55 -070020import android.content.res.Configuration;
Michael Kolb2814a362011-05-19 15:49:41 -070021import android.database.DataSetObserver;
22import android.util.AttributeSet;
23import android.view.MotionEvent;
24import android.view.View;
25import android.view.ViewGroup;
26import android.widget.BaseAdapter;
Michael Kolb4bd767d2011-05-27 11:33:55 -070027import android.widget.FrameLayout;
Michael Kolb2814a362011-05-19 15:49:41 -070028import android.widget.LinearLayout;
29
Michael Kolb4bd767d2011-05-27 11:33:55 -070030import com.android.browser.view.HorizontalScrollView;
31import com.android.browser.view.ScrollView;
32
Michael Kolb2814a362011-05-19 15:49:41 -070033/**
34 * custom view for displaying tabs in the nav screen
35 */
Michael Kolb4bd767d2011-05-27 11:33:55 -070036public class NavTabScroller extends FrameLayout {
Michael Kolb2814a362011-05-19 15:49:41 -070037
38 private LinearLayout mContentView;
Michael Kolb2814a362011-05-19 15:49:41 -070039 private BaseAdapter mAdapter;
Michael Kolb4bd767d2011-05-27 11:33:55 -070040 private SelectableSroller mScroller;
41 private int mOrientation;
Michael Kolb2814a362011-05-19 15:49:41 -070042
43 public NavTabScroller(Context context, AttributeSet attrs, int defStyle) {
44 super(context, attrs, defStyle);
45 init(context);
46 }
47
48 public NavTabScroller(Context context, AttributeSet attrs) {
49 super(context, attrs);
50 init(context);
51 }
52
53 public NavTabScroller(Context context) {
54 super(context);
55 init(context);
56 }
57
58 private void init(Context ctx) {
Michael Kolb4bd767d2011-05-27 11:33:55 -070059 mOrientation = ctx.getResources().getConfiguration().orientation;
60 mScroller = (mOrientation == Configuration.ORIENTATION_LANDSCAPE) ?
61 new HorizontalScroller(ctx) : new VerticalScroller(ctx);
62 mContentView = mScroller.getContentView();
63 View sview = (View) mScroller;
64 sview.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
65 LayoutParams.MATCH_PARENT));
66 addView(sview);
Michael Kolb2814a362011-05-19 15:49:41 -070067 }
68
Michael Kolbdb343c52011-05-29 12:18:52 -070069 @Override
70 protected void onMeasure(int wspec, int hspec) {
71 super.onMeasure(wspec, hspec);
72 calcPadding();
73 }
74
75 private void calcPadding() {
76 if (mAdapter.getCount() > 0) {
77 View v = mContentView.getChildAt(0);
78 if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
79 int pad = (getMeasuredHeight() - v.getMeasuredHeight()) / 2;
80 mContentView.setPadding(0, pad, 0, pad);
81 } else {
82 int pad = (getMeasuredWidth() - v.getMeasuredWidth()) / 2;
83 mContentView.setPadding(pad, 0, pad, 0);
84 }
85 }
86 }
87
Michael Kolb2814a362011-05-19 15:49:41 -070088 protected void setAdapter(BaseAdapter adapter) {
89 mAdapter = adapter;
90 mAdapter.registerDataSetObserver(new DataSetObserver() {
91
92 @Override
93 public void onChanged() {
94 super.onChanged();
95 populateList();
96 }
97
98 @Override
99 public void onInvalidated() {
100 super.onInvalidated();
101 }
102 });
103 populateList();
104 }
105
106 protected void setSelection(int ix) {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700107 mScroller.setSelection(ix);
Michael Kolb2814a362011-05-19 15:49:41 -0700108 }
109
110 protected int getSelectionIndex() {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700111 return mScroller.getSelection();
Michael Kolb2814a362011-05-19 15:49:41 -0700112 }
113
114 protected Tab getSelectedItem() {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700115 return (Tab) mAdapter.getItem(mScroller.getSelection());
Michael Kolb2814a362011-05-19 15:49:41 -0700116 }
117
118 protected ViewGroup getContentView() {
119 return mContentView;
120 }
121
122 private void populateList() {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700123 mContentView.removeAllViewsInLayout();
Michael Kolb2814a362011-05-19 15:49:41 -0700124 for (int i = 0; i < mAdapter.getCount(); i++) {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700125 NavTabView v = (NavTabView) mAdapter.getView(i, null, mContentView);
Michael Kolb2814a362011-05-19 15:49:41 -0700126 mContentView.addView(v);
Michael Kolb2814a362011-05-19 15:49:41 -0700127 }
128 }
129
130 View getSelectedTab() {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700131 int selected = mScroller.getSelection();
132 if ((selected >= 0) && (selected < mContentView.getChildCount())) {
133 return mContentView.getChildAt(selected);
Michael Kolb2814a362011-05-19 15:49:41 -0700134 } else {
135 return null;
136 }
137 }
138
Michael Kolb4bd767d2011-05-27 11:33:55 -0700139 static interface SelectableSroller {
140 void setSelection(int index);
141 int getSelection();
142 LinearLayout getContentView();
143
Michael Kolb2814a362011-05-19 15:49:41 -0700144 }
145
Michael Kolb4bd767d2011-05-27 11:33:55 -0700146 static class VerticalScroller extends ScrollView implements SelectableSroller {
147
148 private LinearLayout mContentView;
149 private int mSelected;
150 private boolean mSnapScroll;
151
152 public VerticalScroller(Context context, AttributeSet attrs, int defStyle) {
153 super(context, attrs, defStyle);
154 init(context);
155 }
156
157 public VerticalScroller(Context context, AttributeSet attrs) {
158 super(context, attrs);
159 init(context);
160 }
161
162 public VerticalScroller(Context context) {
163 super(context);
164 init(context);
165 }
166
167 private void init(Context ctx) {
168 setHorizontalScrollBarEnabled(false);
169 mContentView = new LinearLayout(ctx);
170 mContentView.setOrientation(LinearLayout.VERTICAL);
171 setVerticalScrollBarEnabled(false);
172 setSmoothScrollingEnabled(true);
Michael Kolb4bd767d2011-05-27 11:33:55 -0700173 mContentView.setLayoutParams(
174 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
175 addView(mContentView);
176
177 }
178
179 public LinearLayout getContentView() {
180 return mContentView;
181 }
182
183 public void setSelection(int ix) {
184 mSelected = ix;
185 }
186
187 public int getSelection() {
188 return mSelected;
189 }
190
191 protected void onScrollChanged(int sl, int st, int ol, int ot) {
192 int midy = getScrollY() + getHeight() / 2;
193 int sel = -1;
194 for (int i = 0; i < mContentView.getChildCount(); i++) {
Michael Kolb0f91e032011-06-01 09:54:20 -0700195 NavTabView child = (NavTabView) mContentView.getChildAt(i);
196 int top = child.getTop();
197 int bottom = child.getBottom();
198 if (top <= midy && bottom >= midy) {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700199 sel = i;
Michael Kolb0f91e032011-06-01 09:54:20 -0700200 } else {
201 // check if on screen
202 if (top > getScrollY() + getHeight() || bottom < getScrollY()) {
203 if (!child.isPaused()) {
204 child.pause();
205 }
206 } else {
207 if (child.isPaused()) {
208 child.resume();
209 }
210 }
Michael Kolb4bd767d2011-05-27 11:33:55 -0700211 }
212 }
213 if (sel != -1) {
214 if (sel != mSelected) {
215 setSelection(sel);
216 }
Michael Kolb2814a362011-05-19 15:49:41 -0700217 }
218 }
Michael Kolb2814a362011-05-19 15:49:41 -0700219
Michael Kolb4bd767d2011-05-27 11:33:55 -0700220 @Override
221 public boolean onTouchEvent(MotionEvent evt) {
222 // save drag state before super call
223 boolean dragged = mIsBeingDragged;
224 boolean result = super.onTouchEvent(evt);
225 if (MotionEvent.ACTION_UP == evt.getActionMasked()) {
226 if (mScroller.isFinished() && dragged) {
227 snapToSelected();
228 }
Michael Kolbdb343c52011-05-29 12:18:52 -0700229 } else if (MotionEvent.ACTION_MOVE == evt.getActionMasked()) {
230 NavTabView ntv = (NavTabView) getSelectedView();
231 if (mIsBeingDragged && ntv.isHighlighted()) {
232 ntv.setHighlighted(false);
233 }
Michael Kolb4bd767d2011-05-27 11:33:55 -0700234 }
235 return result;
236 }
237
238 @Override
239 public void computeScroll() {
240 super.computeScroll();
241 if (mScroller.isFinished() && !mIsBeingDragged) {
242 if (!mSnapScroll) {
243 snapToSelected();
244 } else {
245 // reset snap scrolling flag
246 mSnapScroll = false;
247 NavTabView ntv = (NavTabView) getSelectedView();
Michael Kolbdb343c52011-05-29 12:18:52 -0700248 ntv.setHighlighted(true);
Michael Kolb4bd767d2011-05-27 11:33:55 -0700249 }
Michael Kolb2814a362011-05-19 15:49:41 -0700250 }
251 }
Michael Kolb2814a362011-05-19 15:49:41 -0700252
Michael Kolb4bd767d2011-05-27 11:33:55 -0700253 private void snapToSelected() {
254 View v = mContentView.getChildAt(mSelected);
255 int top = (v.getTop() + v.getBottom()) / 2;
256 top -= getHeight() / 2;
257 if (top != getScrollY()) {
258 // snap to selected
259 mSnapScroll = true;
260 smoothScrollTo(0, top);
Michael Kolbdb343c52011-05-29 12:18:52 -0700261 } else {
262 NavTabView ntv = (NavTabView) getSelectedView();
263 ntv.setHighlighted(true);
Michael Kolb2814a362011-05-19 15:49:41 -0700264 }
265 }
Michael Kolb4bd767d2011-05-27 11:33:55 -0700266
267 protected View getSelectedView() {
268 return mContentView.getChildAt(mSelected);
269 }
270
Michael Kolb2814a362011-05-19 15:49:41 -0700271 }
272
Michael Kolb4bd767d2011-05-27 11:33:55 -0700273 static class HorizontalScroller extends HorizontalScrollView implements SelectableSroller {
274
275 private LinearLayout mContentView;
276 private int mSelected;
277 private boolean mSnapScroll;
278
279 public HorizontalScroller(Context context, AttributeSet attrs, int defStyle) {
280 super(context, attrs, defStyle);
281 init(context);
282 }
283
284 public HorizontalScroller(Context context, AttributeSet attrs) {
285 super(context, attrs);
286 init(context);
287 }
288
289 public HorizontalScroller(Context context) {
290 super(context);
291 init(context);
292 }
293
294 private void init(Context ctx) {
295 setHorizontalScrollBarEnabled(false);
296 mContentView = new LinearLayout(ctx);
297 mContentView.setOrientation(LinearLayout.HORIZONTAL);
298 setVerticalScrollBarEnabled(false);
299 setSmoothScrollingEnabled(true);
Michael Kolb4bd767d2011-05-27 11:33:55 -0700300 mContentView.setLayoutParams(
301 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
302 addView(mContentView);
Michael Kolb4bd767d2011-05-27 11:33:55 -0700303 }
304
305 public LinearLayout getContentView() {
306 return mContentView;
307 }
308
309 public void setSelection(int ix) {
310 mSelected = ix;
311 }
312
313 public int getSelection() {
314 return mSelected;
315 }
316
317 protected void onScrollChanged(int sl, int st, int ol, int ot) {
318 int midx = getScrollX() + getWidth() / 2;
319 int sel = -1;
320 for (int i = 0; i < mContentView.getChildCount(); i++) {
321 View child = mContentView.getChildAt(i);
322 if (child.getLeft() <= midx && child.getRight() >= midx) {
323 sel = i;
324 break;
325 }
326 }
327 if (sel != -1) {
328 if (sel != mSelected) {
329 setSelection(sel);
330 }
Michael Kolb4bd767d2011-05-27 11:33:55 -0700331 }
332 }
333
334 @Override
335 public boolean onTouchEvent(MotionEvent evt) {
336 // save drag state before super call
337 boolean dragged = mIsBeingDragged;
338 boolean result = super.onTouchEvent(evt);
339 if (MotionEvent.ACTION_UP == evt.getActionMasked()) {
340 if (mScroller.isFinished() && dragged) {
341 snapToSelected();
342 }
Michael Kolbdb343c52011-05-29 12:18:52 -0700343 } else if (MotionEvent.ACTION_MOVE == evt.getActionMasked()) {
344 NavTabView ntv = (NavTabView) getSelectedView();
345 if (mIsBeingDragged && ntv.isHighlighted()) {
346 ntv.setHighlighted(false);
347 }
Michael Kolb4bd767d2011-05-27 11:33:55 -0700348 }
349 return result;
350 }
351
352 @Override
353 public void computeScroll() {
354 super.computeScroll();
355 if (mScroller.isFinished() && !mIsBeingDragged) {
356 if (!mSnapScroll) {
357 snapToSelected();
358 } else {
359 // reset snap scrolling flag
360 mSnapScroll = false;
361 NavTabView ntv = (NavTabView) getSelectedView();
Michael Kolbdb343c52011-05-29 12:18:52 -0700362 ntv.setHighlighted(true);
Michael Kolb4bd767d2011-05-27 11:33:55 -0700363 }
364 }
365 }
366
Michael Kolb4bd767d2011-05-27 11:33:55 -0700367 private void snapToSelected() {
368 View v = mContentView.getChildAt(mSelected);
369 int left = (v.getLeft() + v.getRight()) / 2;
370 left -= getWidth() / 2;
371 if (left != getScrollX()) {
372 // snap to selected
373 mSnapScroll = true;
374 smoothScrollTo(left, 0);
Michael Kolbdb343c52011-05-29 12:18:52 -0700375 } else {
376 NavTabView ntv = (NavTabView) getSelectedView();
377 ntv.setHighlighted(true);
Michael Kolb4bd767d2011-05-27 11:33:55 -0700378 }
379 }
380
381 protected View getSelectedView() {
382 return mContentView.getChildAt(mSelected);
383 }
384
Michael Kolb2814a362011-05-19 15:49:41 -0700385 }
386
387}