blob: cbb2cfdcaa5c5e3c39642a3f937f99552563aec9 [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
69 protected void setAdapter(BaseAdapter adapter) {
70 mAdapter = adapter;
71 mAdapter.registerDataSetObserver(new DataSetObserver() {
72
73 @Override
74 public void onChanged() {
75 super.onChanged();
76 populateList();
77 }
78
79 @Override
80 public void onInvalidated() {
81 super.onInvalidated();
82 }
83 });
84 populateList();
85 }
86
87 protected void setSelection(int ix) {
Michael Kolb4bd767d2011-05-27 11:33:55 -070088 mScroller.setSelection(ix);
Michael Kolb2814a362011-05-19 15:49:41 -070089 }
90
91 protected int getSelectionIndex() {
Michael Kolb4bd767d2011-05-27 11:33:55 -070092 return mScroller.getSelection();
Michael Kolb2814a362011-05-19 15:49:41 -070093 }
94
95 protected Tab getSelectedItem() {
Michael Kolb4bd767d2011-05-27 11:33:55 -070096 return (Tab) mAdapter.getItem(mScroller.getSelection());
Michael Kolb2814a362011-05-19 15:49:41 -070097 }
98
99 protected ViewGroup getContentView() {
100 return mContentView;
101 }
102
103 private void populateList() {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700104 mContentView.removeAllViewsInLayout();
Michael Kolb2814a362011-05-19 15:49:41 -0700105 for (int i = 0; i < mAdapter.getCount(); i++) {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700106 NavTabView v = (NavTabView) mAdapter.getView(i, null, mContentView);
Michael Kolb2814a362011-05-19 15:49:41 -0700107 mContentView.addView(v);
Michael Kolb2814a362011-05-19 15:49:41 -0700108 }
109 }
110
111 View getSelectedTab() {
Michael Kolb4bd767d2011-05-27 11:33:55 -0700112 int selected = mScroller.getSelection();
113 if ((selected >= 0) && (selected < mContentView.getChildCount())) {
114 return mContentView.getChildAt(selected);
Michael Kolb2814a362011-05-19 15:49:41 -0700115 } else {
116 return null;
117 }
118 }
119
Michael Kolb4bd767d2011-05-27 11:33:55 -0700120 static interface SelectableSroller {
121 void setSelection(int index);
122 int getSelection();
123 LinearLayout getContentView();
124
Michael Kolb2814a362011-05-19 15:49:41 -0700125 }
126
Michael Kolb4bd767d2011-05-27 11:33:55 -0700127 static class VerticalScroller extends ScrollView implements SelectableSroller {
128
129 private LinearLayout mContentView;
130 private int mSelected;
131 private boolean mSnapScroll;
132
133 public VerticalScroller(Context context, AttributeSet attrs, int defStyle) {
134 super(context, attrs, defStyle);
135 init(context);
136 }
137
138 public VerticalScroller(Context context, AttributeSet attrs) {
139 super(context, attrs);
140 init(context);
141 }
142
143 public VerticalScroller(Context context) {
144 super(context);
145 init(context);
146 }
147
148 private void init(Context ctx) {
149 setHorizontalScrollBarEnabled(false);
150 mContentView = new LinearLayout(ctx);
151 mContentView.setOrientation(LinearLayout.VERTICAL);
152 setVerticalScrollBarEnabled(false);
153 setSmoothScrollingEnabled(true);
154 int pad = ctx.getResources().getDimensionPixelSize(R.dimen.nav_scroller_padding);
155 mContentView.setPadding(0, pad, 0, pad);
156 mContentView.setLayoutParams(
157 new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
158 addView(mContentView);
159
160 }
161
162 public LinearLayout getContentView() {
163 return mContentView;
164 }
165
166 public void setSelection(int ix) {
167 mSelected = ix;
168 }
169
170 public int getSelection() {
171 return mSelected;
172 }
173
174 protected void onScrollChanged(int sl, int st, int ol, int ot) {
175 int midy = getScrollY() + getHeight() / 2;
176 int sel = -1;
177 for (int i = 0; i < mContentView.getChildCount(); i++) {
178 View child = mContentView.getChildAt(i);
179 if (child.getTop() <= midy && child.getBottom() >= midy) {
180 sel = i;
181 break;
182 }
183 }
184 if (sel != -1) {
185 if (sel != mSelected) {
186 setSelection(sel);
187 }
188 if (!isCentered(mSelected)) {
189 NavTabView ntv = (NavTabView) getSelectedView();
190 ntv.setHighlighted(false);
191 }
Michael Kolb2814a362011-05-19 15:49:41 -0700192 }
193 }
Michael Kolb2814a362011-05-19 15:49:41 -0700194
Michael Kolb4bd767d2011-05-27 11:33:55 -0700195 @Override
196 public boolean onTouchEvent(MotionEvent evt) {
197 // save drag state before super call
198 boolean dragged = mIsBeingDragged;
199 boolean result = super.onTouchEvent(evt);
200 if (MotionEvent.ACTION_UP == evt.getActionMasked()) {
201 if (mScroller.isFinished() && dragged) {
202 snapToSelected();
203 }
204 }
205 return result;
206 }
207
208 @Override
209 public void computeScroll() {
210 super.computeScroll();
211 if (mScroller.isFinished() && !mIsBeingDragged) {
212 if (!mSnapScroll) {
213 snapToSelected();
214 } else {
215 // reset snap scrolling flag
216 mSnapScroll = false;
217 NavTabView ntv = (NavTabView) getSelectedView();
218 ntv.setHighlighted(isCentered(mSelected));
219 }
Michael Kolb2814a362011-05-19 15:49:41 -0700220 }
221 }
Michael Kolb2814a362011-05-19 15:49:41 -0700222
Michael Kolb4bd767d2011-05-27 11:33:55 -0700223 private boolean isCentered(int ix) {
224 int midy = getScrollY() + (getTop() + getBottom()) / 2;
225 View v = mContentView.getChildAt(ix);
226 return (v.getTop() + v.getBottom()) / 2 == midy;
227 }
228
229 private void snapToSelected() {
230 View v = mContentView.getChildAt(mSelected);
231 int top = (v.getTop() + v.getBottom()) / 2;
232 top -= getHeight() / 2;
233 if (top != getScrollY()) {
234 // snap to selected
235 mSnapScroll = true;
236 smoothScrollTo(0, top);
Michael Kolb2814a362011-05-19 15:49:41 -0700237 }
238 }
Michael Kolb4bd767d2011-05-27 11:33:55 -0700239
240 protected View getSelectedView() {
241 return mContentView.getChildAt(mSelected);
242 }
243
Michael Kolb2814a362011-05-19 15:49:41 -0700244 }
245
Michael Kolb4bd767d2011-05-27 11:33:55 -0700246 static class HorizontalScroller extends HorizontalScrollView implements SelectableSroller {
247
248 private LinearLayout mContentView;
249 private int mSelected;
250 private boolean mSnapScroll;
251
252 public HorizontalScroller(Context context, AttributeSet attrs, int defStyle) {
253 super(context, attrs, defStyle);
254 init(context);
255 }
256
257 public HorizontalScroller(Context context, AttributeSet attrs) {
258 super(context, attrs);
259 init(context);
260 }
261
262 public HorizontalScroller(Context context) {
263 super(context);
264 init(context);
265 }
266
267 private void init(Context ctx) {
268 setHorizontalScrollBarEnabled(false);
269 mContentView = new LinearLayout(ctx);
270 mContentView.setOrientation(LinearLayout.HORIZONTAL);
271 setVerticalScrollBarEnabled(false);
272 setSmoothScrollingEnabled(true);
273 int pad = ctx.getResources().getDimensionPixelSize(R.dimen.nav_scroller_padding);
274 mContentView.setPadding(pad, 0, pad, 0);
275 mContentView.setLayoutParams(
276 new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
277 addView(mContentView);
278
279 }
280
281 public LinearLayout getContentView() {
282 return mContentView;
283 }
284
285 public void setSelection(int ix) {
286 mSelected = ix;
287 }
288
289 public int getSelection() {
290 return mSelected;
291 }
292
293 protected void onScrollChanged(int sl, int st, int ol, int ot) {
294 int midx = getScrollX() + getWidth() / 2;
295 int sel = -1;
296 for (int i = 0; i < mContentView.getChildCount(); i++) {
297 View child = mContentView.getChildAt(i);
298 if (child.getLeft() <= midx && child.getRight() >= midx) {
299 sel = i;
300 break;
301 }
302 }
303 if (sel != -1) {
304 if (sel != mSelected) {
305 setSelection(sel);
306 }
307 if (!isCentered(mSelected)) {
308 NavTabView ntv = (NavTabView) getSelectedView();
309 ntv.setHighlighted(false);
310 }
311 }
312 }
313
314 @Override
315 public boolean onTouchEvent(MotionEvent evt) {
316 // save drag state before super call
317 boolean dragged = mIsBeingDragged;
318 boolean result = super.onTouchEvent(evt);
319 if (MotionEvent.ACTION_UP == evt.getActionMasked()) {
320 if (mScroller.isFinished() && dragged) {
321 snapToSelected();
322 }
323 }
324 return result;
325 }
326
327 @Override
328 public void computeScroll() {
329 super.computeScroll();
330 if (mScroller.isFinished() && !mIsBeingDragged) {
331 if (!mSnapScroll) {
332 snapToSelected();
333 } else {
334 // reset snap scrolling flag
335 mSnapScroll = false;
336 NavTabView ntv = (NavTabView) getSelectedView();
337 ntv.setHighlighted(isCentered(mSelected));
338 }
339 }
340 }
341
342 private boolean isCentered(int ix) {
343 int midx = getScrollX() + getWidth() / 2;
344 View v = mContentView.getChildAt(ix);
345 return (v.getLeft() + v.getRight()) / 2 == midx;
346 }
347
348 private void snapToSelected() {
349 View v = mContentView.getChildAt(mSelected);
350 int left = (v.getLeft() + v.getRight()) / 2;
351 left -= getWidth() / 2;
352 if (left != getScrollX()) {
353 // snap to selected
354 mSnapScroll = true;
355 smoothScrollTo(left, 0);
356 }
357 }
358
359 protected View getSelectedView() {
360 return mContentView.getChildAt(mSelected);
361 }
362
Michael Kolb2814a362011-05-19 15:49:41 -0700363 }
364
365}