/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.browser; import android.content.Context; import android.content.res.Configuration; import android.database.DataSetObserver; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.LinearLayout; import com.android.browser.view.HorizontalScrollView; import com.android.browser.view.ScrollView; /** * custom view for displaying tabs in the nav screen */ public class NavTabScroller extends FrameLayout { private LinearLayout mContentView; private BaseAdapter mAdapter; private SelectableSroller mScroller; private int mOrientation; public NavTabScroller(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public NavTabScroller(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public NavTabScroller(Context context) { super(context); init(context); } private void init(Context ctx) { mOrientation = ctx.getResources().getConfiguration().orientation; mScroller = (mOrientation == Configuration.ORIENTATION_LANDSCAPE) ? new HorizontalScroller(ctx) : new VerticalScroller(ctx); mContentView = mScroller.getContentView(); View sview = (View) mScroller; sview.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); addView(sview); } @Override protected void onMeasure(int wspec, int hspec) { super.onMeasure(wspec, hspec); calcPadding(); } private void calcPadding() { if (mAdapter.getCount() > 0) { View v = mContentView.getChildAt(0); if (mOrientation == Configuration.ORIENTATION_PORTRAIT) { int pad = (getMeasuredHeight() - v.getMeasuredHeight()) / 2; mContentView.setPadding(0, pad, 0, pad); } else { int pad = (getMeasuredWidth() - v.getMeasuredWidth()) / 2; mContentView.setPadding(pad, 0, pad, 0); } } } protected void setAdapter(BaseAdapter adapter) { mAdapter = adapter; mAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { super.onChanged(); populateList(); } @Override public void onInvalidated() { super.onInvalidated(); } }); populateList(); } protected void setSelection(int ix) { mScroller.setSelection(ix); } protected int getSelectionIndex() { return mScroller.getSelection(); } protected Tab getSelectedItem() { return (Tab) mAdapter.getItem(mScroller.getSelection()); } protected ViewGroup getContentView() { return mContentView; } private void populateList() { mContentView.removeAllViewsInLayout(); for (int i = 0; i < mAdapter.getCount(); i++) { NavTabView v = (NavTabView) mAdapter.getView(i, null, mContentView); mContentView.addView(v); } } View getSelectedTab() { int selected = mScroller.getSelection(); if ((selected >= 0) && (selected < mContentView.getChildCount())) { return mContentView.getChildAt(selected); } else { return null; } } static interface SelectableSroller { void setSelection(int index); int getSelection(); LinearLayout getContentView(); } static class VerticalScroller extends ScrollView implements SelectableSroller { private LinearLayout mContentView; private int mSelected; private boolean mSnapScroll; public VerticalScroller(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public VerticalScroller(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public VerticalScroller(Context context) { super(context); init(context); } private void init(Context ctx) { setHorizontalScrollBarEnabled(false); mContentView = new LinearLayout(ctx); mContentView.setOrientation(LinearLayout.VERTICAL); setVerticalScrollBarEnabled(false); setSmoothScrollingEnabled(true); mContentView.setLayoutParams( new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); addView(mContentView); } public LinearLayout getContentView() { return mContentView; } public void setSelection(int ix) { mSelected = ix; } public int getSelection() { return mSelected; } protected void onScrollChanged(int sl, int st, int ol, int ot) { int midy = getScrollY() + getHeight() / 2; int sel = -1; for (int i = 0; i < mContentView.getChildCount(); i++) { NavTabView child = (NavTabView) mContentView.getChildAt(i); int top = child.getTop(); int bottom = child.getBottom(); if (top <= midy && bottom >= midy) { sel = i; } else { // check if on screen if (top > getScrollY() + getHeight() || bottom < getScrollY()) { if (!child.isPaused()) { child.pause(); } } else { if (child.isPaused()) { child.resume(); } } } } if (sel != -1) { if (sel != mSelected) { setSelection(sel); } } } @Override public boolean onTouchEvent(MotionEvent evt) { // save drag state before super call boolean dragged = mIsBeingDragged; boolean result = super.onTouchEvent(evt); if (MotionEvent.ACTION_UP == evt.getActionMasked()) { if (mScroller.isFinished() && dragged) { snapToSelected(); } } else if (MotionEvent.ACTION_MOVE == evt.getActionMasked()) { NavTabView ntv = (NavTabView) getSelectedView(); if (mIsBeingDragged && ntv.isHighlighted()) { ntv.setHighlighted(false); } } return result; } @Override public void computeScroll() { super.computeScroll(); if (mScroller.isFinished() && !mIsBeingDragged) { if (!mSnapScroll) { snapToSelected(); } else { // reset snap scrolling flag mSnapScroll = false; NavTabView ntv = (NavTabView) getSelectedView(); ntv.setHighlighted(true); } } } private void snapToSelected() { View v = mContentView.getChildAt(mSelected); int top = (v.getTop() + v.getBottom()) / 2; top -= getHeight() / 2; if (top != getScrollY()) { // snap to selected mSnapScroll = true; smoothScrollTo(0, top); } else { NavTabView ntv = (NavTabView) getSelectedView(); ntv.setHighlighted(true); } } protected View getSelectedView() { return mContentView.getChildAt(mSelected); } } static class HorizontalScroller extends HorizontalScrollView implements SelectableSroller { private LinearLayout mContentView; private int mSelected; private boolean mSnapScroll; public HorizontalScroller(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public HorizontalScroller(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public HorizontalScroller(Context context) { super(context); init(context); } private void init(Context ctx) { setHorizontalScrollBarEnabled(false); mContentView = new LinearLayout(ctx); mContentView.setOrientation(LinearLayout.HORIZONTAL); setVerticalScrollBarEnabled(false); setSmoothScrollingEnabled(true); mContentView.setLayoutParams( new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); addView(mContentView); } public LinearLayout getContentView() { return mContentView; } public void setSelection(int ix) { mSelected = ix; } public int getSelection() { return mSelected; } protected void onScrollChanged(int sl, int st, int ol, int ot) { int midx = getScrollX() + getWidth() / 2; int sel = -1; for (int i = 0; i < mContentView.getChildCount(); i++) { View child = mContentView.getChildAt(i); if (child.getLeft() <= midx && child.getRight() >= midx) { sel = i; break; } } if (sel != -1) { if (sel != mSelected) { setSelection(sel); } } } @Override public boolean onTouchEvent(MotionEvent evt) { // save drag state before super call boolean dragged = mIsBeingDragged; boolean result = super.onTouchEvent(evt); if (MotionEvent.ACTION_UP == evt.getActionMasked()) { if (mScroller.isFinished() && dragged) { snapToSelected(); } } else if (MotionEvent.ACTION_MOVE == evt.getActionMasked()) { NavTabView ntv = (NavTabView) getSelectedView(); if (mIsBeingDragged && ntv.isHighlighted()) { ntv.setHighlighted(false); } } return result; } @Override public void computeScroll() { super.computeScroll(); if (mScroller.isFinished() && !mIsBeingDragged) { if (!mSnapScroll) { snapToSelected(); } else { // reset snap scrolling flag mSnapScroll = false; NavTabView ntv = (NavTabView) getSelectedView(); ntv.setHighlighted(true); } } } private void snapToSelected() { View v = mContentView.getChildAt(mSelected); int left = (v.getLeft() + v.getRight()) / 2; left -= getWidth() / 2; if (left != getScrollX()) { // snap to selected mSnapScroll = true; smoothScrollTo(left, 0); } else { NavTabView ntv = (NavTabView) getSelectedView(); ntv.setHighlighted(true); } } protected View getSelectedView() { return mContentView.getChildAt(mSelected); } } }