mobile/android/base/home/TabMenuStripLayout.java

branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
equal deleted inserted replaced
-1:000000000000 0:9af0faeded3f
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 package org.mozilla.gecko.home;
7
8 import org.mozilla.gecko.R;
9
10 import android.content.Context;
11 import android.content.res.TypedArray;
12 import android.graphics.Canvas;
13 import android.graphics.drawable.Drawable;
14 import android.util.AttributeSet;
15 import android.view.LayoutInflater;
16 import android.view.View;
17 import android.view.ViewTreeObserver;
18 import android.view.accessibility.AccessibilityEvent;
19 import android.widget.LinearLayout;
20 import android.widget.TextView;
21
22 /**
23 * {@code TabMenuStripLayout} is the view that draws the {@code HomePager}
24 * tabs that are displayed in {@code TabMenuStrip}.
25 */
26 class TabMenuStripLayout extends LinearLayout
27 implements View.OnFocusChangeListener {
28
29 private HomePager.OnTitleClickListener onTitleClickListener;
30 private Drawable strip;
31 private View selectedView;
32
33 // Data associated with the scrolling of the strip drawable.
34 private View toTab;
35 private View fromTab;
36 private float progress;
37
38 // This variable is used to predict the direction of scroll.
39 private float prevProgress;
40
41 TabMenuStripLayout(Context context, AttributeSet attrs) {
42 super(context, attrs);
43
44 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabMenuStrip);
45 final int stripResId = a.getResourceId(R.styleable.TabMenuStrip_strip, -1);
46 a.recycle();
47
48 if (stripResId != -1) {
49 strip = getResources().getDrawable(stripResId);
50 }
51
52 setWillNotDraw(false);
53 }
54
55 void onAddPagerView(String title) {
56 final TextView button = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.tab_menu_strip, this, false);
57 button.setText(title.toUpperCase());
58
59 addView(button);
60 button.setOnClickListener(new ViewClickListener(getChildCount() - 1));
61 button.setOnFocusChangeListener(this);
62 }
63
64 void onPageSelected(final int position) {
65 selectedView = getChildAt(position);
66
67 // Callback to measure and draw the strip after the view is visible.
68 ViewTreeObserver vto = selectedView.getViewTreeObserver();
69 if (vto.isAlive()) {
70 vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
71 @Override
72 public void onGlobalLayout() {
73 selectedView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
74
75 if (strip != null) {
76 strip.setBounds(selectedView.getLeft(),
77 selectedView.getTop(),
78 selectedView.getRight(),
79 selectedView.getBottom());
80 }
81
82 prevProgress = position;
83 }
84 });
85 }
86 }
87
88 // Page scroll animates the drawable and its bounds from the previous to next child view.
89 void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
90 if (strip == null) {
91 return;
92 }
93
94 setScrollingData(position, positionOffset);
95
96 if (fromTab == null || toTab == null) {
97 return;
98 }
99
100 final int fromTabLeft = fromTab.getLeft();
101 final int fromTabRight = fromTab.getRight();
102
103 final int toTabLeft = toTab.getLeft();
104 final int toTabRight = toTab.getRight();
105
106 strip.setBounds((int) (fromTabLeft + ((toTabLeft - fromTabLeft) * progress)),
107 0,
108 (int) (fromTabRight + ((toTabRight - fromTabRight) * progress)),
109 getHeight());
110 invalidate();
111 }
112
113 /*
114 * position + positionOffset goes from 0 to 2 as we scroll from page 1 to 3.
115 * Normalized progress is relative to the the direction the page is being scrolled towards.
116 * For this, we maintain direction of scroll with a state, and the child view we are moving towards and away from.
117 */
118 void setScrollingData(int position, float positionOffset) {
119 if (position >= getChildCount() - 1) {
120 return;
121 }
122
123 final float currProgress = position + positionOffset;
124
125 if (prevProgress > currProgress) {
126 toTab = getChildAt(position);
127 fromTab = getChildAt(position + 1);
128 progress = 1 - positionOffset;
129 } else {
130 toTab = getChildAt(position + 1);
131 fromTab = getChildAt(position);
132 progress = positionOffset;
133 }
134
135 prevProgress = currProgress;
136 }
137
138 @Override
139 public void onDraw(Canvas canvas) {
140 super.onDraw(canvas);
141
142 if (strip != null) {
143 strip.draw(canvas);
144 }
145 }
146
147 @Override
148 public void onFocusChange(View v, boolean hasFocus) {
149 if (v == this && hasFocus && getChildCount() > 0) {
150 selectedView.requestFocus();
151 return;
152 }
153
154 if (!hasFocus) {
155 return;
156 }
157
158 int i = 0;
159 final int numTabs = getChildCount();
160
161 while (i < numTabs) {
162 View view = getChildAt(i);
163 if (view == v) {
164 view.requestFocus();
165 if (isShown()) {
166 // A view is focused so send an event to announce the menu strip state.
167 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
168 }
169 break;
170 }
171
172 i++;
173 }
174 }
175
176 void setOnTitleClickListener(HomePager.OnTitleClickListener onTitleClickListener) {
177 this.onTitleClickListener = onTitleClickListener;
178 }
179
180 private class ViewClickListener implements OnClickListener {
181 private final int mIndex;
182
183 public ViewClickListener(int index) {
184 mIndex = index;
185 }
186
187 @Override
188 public void onClick(View view) {
189 if (onTitleClickListener != null) {
190 onTitleClickListener.onTitleClicked(mIndex);
191 }
192 }
193 }
194 }

mercurial