michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.home; michael@0: michael@0: import org.mozilla.gecko.R; michael@0: michael@0: import android.content.Context; michael@0: import android.content.res.TypedArray; michael@0: import android.graphics.Canvas; michael@0: import android.graphics.drawable.Drawable; michael@0: import android.util.AttributeSet; michael@0: import android.view.LayoutInflater; michael@0: import android.view.View; michael@0: import android.view.ViewTreeObserver; michael@0: import android.view.accessibility.AccessibilityEvent; michael@0: import android.widget.LinearLayout; michael@0: import android.widget.TextView; michael@0: michael@0: /** michael@0: * {@code TabMenuStripLayout} is the view that draws the {@code HomePager} michael@0: * tabs that are displayed in {@code TabMenuStrip}. michael@0: */ michael@0: class TabMenuStripLayout extends LinearLayout michael@0: implements View.OnFocusChangeListener { michael@0: michael@0: private HomePager.OnTitleClickListener onTitleClickListener; michael@0: private Drawable strip; michael@0: private View selectedView; michael@0: michael@0: // Data associated with the scrolling of the strip drawable. michael@0: private View toTab; michael@0: private View fromTab; michael@0: private float progress; michael@0: michael@0: // This variable is used to predict the direction of scroll. michael@0: private float prevProgress; michael@0: michael@0: TabMenuStripLayout(Context context, AttributeSet attrs) { michael@0: super(context, attrs); michael@0: michael@0: TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabMenuStrip); michael@0: final int stripResId = a.getResourceId(R.styleable.TabMenuStrip_strip, -1); michael@0: a.recycle(); michael@0: michael@0: if (stripResId != -1) { michael@0: strip = getResources().getDrawable(stripResId); michael@0: } michael@0: michael@0: setWillNotDraw(false); michael@0: } michael@0: michael@0: void onAddPagerView(String title) { michael@0: final TextView button = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.tab_menu_strip, this, false); michael@0: button.setText(title.toUpperCase()); michael@0: michael@0: addView(button); michael@0: button.setOnClickListener(new ViewClickListener(getChildCount() - 1)); michael@0: button.setOnFocusChangeListener(this); michael@0: } michael@0: michael@0: void onPageSelected(final int position) { michael@0: selectedView = getChildAt(position); michael@0: michael@0: // Callback to measure and draw the strip after the view is visible. michael@0: ViewTreeObserver vto = selectedView.getViewTreeObserver(); michael@0: if (vto.isAlive()) { michael@0: vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { michael@0: @Override michael@0: public void onGlobalLayout() { michael@0: selectedView.getViewTreeObserver().removeGlobalOnLayoutListener(this); michael@0: michael@0: if (strip != null) { michael@0: strip.setBounds(selectedView.getLeft(), michael@0: selectedView.getTop(), michael@0: selectedView.getRight(), michael@0: selectedView.getBottom()); michael@0: } michael@0: michael@0: prevProgress = position; michael@0: } michael@0: }); michael@0: } michael@0: } michael@0: michael@0: // Page scroll animates the drawable and its bounds from the previous to next child view. michael@0: void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { michael@0: if (strip == null) { michael@0: return; michael@0: } michael@0: michael@0: setScrollingData(position, positionOffset); michael@0: michael@0: if (fromTab == null || toTab == null) { michael@0: return; michael@0: } michael@0: michael@0: final int fromTabLeft = fromTab.getLeft(); michael@0: final int fromTabRight = fromTab.getRight(); michael@0: michael@0: final int toTabLeft = toTab.getLeft(); michael@0: final int toTabRight = toTab.getRight(); michael@0: michael@0: strip.setBounds((int) (fromTabLeft + ((toTabLeft - fromTabLeft) * progress)), michael@0: 0, michael@0: (int) (fromTabRight + ((toTabRight - fromTabRight) * progress)), michael@0: getHeight()); michael@0: invalidate(); michael@0: } michael@0: michael@0: /* michael@0: * position + positionOffset goes from 0 to 2 as we scroll from page 1 to 3. michael@0: * Normalized progress is relative to the the direction the page is being scrolled towards. michael@0: * For this, we maintain direction of scroll with a state, and the child view we are moving towards and away from. michael@0: */ michael@0: void setScrollingData(int position, float positionOffset) { michael@0: if (position >= getChildCount() - 1) { michael@0: return; michael@0: } michael@0: michael@0: final float currProgress = position + positionOffset; michael@0: michael@0: if (prevProgress > currProgress) { michael@0: toTab = getChildAt(position); michael@0: fromTab = getChildAt(position + 1); michael@0: progress = 1 - positionOffset; michael@0: } else { michael@0: toTab = getChildAt(position + 1); michael@0: fromTab = getChildAt(position); michael@0: progress = positionOffset; michael@0: } michael@0: michael@0: prevProgress = currProgress; michael@0: } michael@0: michael@0: @Override michael@0: public void onDraw(Canvas canvas) { michael@0: super.onDraw(canvas); michael@0: michael@0: if (strip != null) { michael@0: strip.draw(canvas); michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: public void onFocusChange(View v, boolean hasFocus) { michael@0: if (v == this && hasFocus && getChildCount() > 0) { michael@0: selectedView.requestFocus(); michael@0: return; michael@0: } michael@0: michael@0: if (!hasFocus) { michael@0: return; michael@0: } michael@0: michael@0: int i = 0; michael@0: final int numTabs = getChildCount(); michael@0: michael@0: while (i < numTabs) { michael@0: View view = getChildAt(i); michael@0: if (view == v) { michael@0: view.requestFocus(); michael@0: if (isShown()) { michael@0: // A view is focused so send an event to announce the menu strip state. michael@0: sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: i++; michael@0: } michael@0: } michael@0: michael@0: void setOnTitleClickListener(HomePager.OnTitleClickListener onTitleClickListener) { michael@0: this.onTitleClickListener = onTitleClickListener; michael@0: } michael@0: michael@0: private class ViewClickListener implements OnClickListener { michael@0: private final int mIndex; michael@0: michael@0: public ViewClickListener(int index) { michael@0: mIndex = index; michael@0: } michael@0: michael@0: @Override michael@0: public void onClick(View view) { michael@0: if (onTitleClickListener != null) { michael@0: onTitleClickListener.onTitleClicked(mIndex); michael@0: } michael@0: } michael@0: } michael@0: }