• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.contacts.common.list;
17 
18 import android.content.Context;
19 import android.content.res.ColorStateList;
20 import android.content.res.TypedArray;
21 import android.graphics.Outline;
22 import android.support.v4.view.PagerAdapter;
23 import android.support.v4.view.ViewPager;
24 import android.util.AttributeSet;
25 import android.util.TypedValue;
26 import android.view.Gravity;
27 import android.view.View;
28 import android.view.ViewOutlineProvider;
29 import android.widget.FrameLayout;
30 import android.widget.HorizontalScrollView;
31 import android.widget.LinearLayout;
32 import android.widget.TextView;
33 import android.widget.Toast;
34 
35 import com.android.contacts.common.R;
36 
37 /**
38  * Lightweight implementation of ViewPager tabs. This looks similar to traditional actionBar tabs,
39  * but allows for the view containing the tabs to be placed anywhere on screen. Text-related
40  * attributes can also be assigned in XML - these will get propogated to the child TextViews
41  * automatically.
42  */
43 public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnPageChangeListener {
44 
45     ViewPager mPager;
46     private ViewPagerTabStrip mTabStrip;
47 
48     /**
49      * Linearlayout that will contain the TextViews serving as tabs. This is the only child
50      * of the parent HorizontalScrollView.
51      */
52     final int mTextStyle;
53     final ColorStateList mTextColor;
54     final int mTextSize;
55     final boolean mTextAllCaps;
56     int mPrevSelected = -1;
57     int mSidePadding;
58 
59     private int[] mTabIcons;
60 
61     private static final ViewOutlineProvider VIEW_BOUNDS_OUTLINE_PROVIDER =
62             new ViewOutlineProvider() {
63         @Override
64         public void getOutline(View view, Outline outline) {
65             outline.setRect(0, 0, view.getWidth(), view.getHeight());
66         }
67     };
68 
69     private static final int TAB_SIDE_PADDING_IN_DPS = 10;
70 
71     // TODO: This should use <declare-styleable> in the future
72     private static final int[] ATTRS = new int[] {
73         android.R.attr.textSize,
74         android.R.attr.textStyle,
75         android.R.attr.textColor,
76         android.R.attr.textAllCaps
77     };
78 
79     /**
80      * Simulates actionbar tab behavior by showing a toast with the tab title when long clicked.
81      */
82     private class OnTabLongClickListener implements OnLongClickListener {
83         final int mPosition;
84 
OnTabLongClickListener(int position)85         public OnTabLongClickListener(int position) {
86             mPosition = position;
87         }
88 
89         @Override
onLongClick(View v)90         public boolean onLongClick(View v) {
91             final int[] screenPos = new int[2];
92             getLocationOnScreen(screenPos);
93 
94             final Context context = getContext();
95             final int width = getWidth();
96             final int height = getHeight();
97             final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
98 
99             Toast toast = Toast.makeText(context, mPager.getAdapter().getPageTitle(mPosition),
100                     Toast.LENGTH_SHORT);
101 
102             // Show the toast under the tab
103             toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL,
104                     (screenPos[0] + width / 2) - screenWidth / 2, screenPos[1] + height);
105 
106             toast.show();
107             return true;
108         }
109     }
110 
ViewPagerTabs(Context context)111     public ViewPagerTabs(Context context) {
112         this(context, null);
113     }
114 
ViewPagerTabs(Context context, AttributeSet attrs)115     public ViewPagerTabs(Context context, AttributeSet attrs) {
116         this(context, attrs, 0);
117     }
118 
ViewPagerTabs(Context context, AttributeSet attrs, int defStyle)119     public ViewPagerTabs(Context context, AttributeSet attrs, int defStyle) {
120         super(context, attrs, defStyle);
121         setFillViewport(true);
122 
123         mSidePadding = (int) (getResources().getDisplayMetrics().density * TAB_SIDE_PADDING_IN_DPS);
124 
125         final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
126         mTextSize = a.getDimensionPixelSize(0, 0);
127         mTextStyle = a.getInt(1, 0);
128         mTextColor = a.getColorStateList(2);
129         mTextAllCaps = a.getBoolean(3, false);
130 
131         mTabStrip = new ViewPagerTabStrip(context);
132         addView(mTabStrip,
133                 new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
134         a.recycle();
135 
136         // enable shadow casting from view bounds
137         setOutlineProvider(VIEW_BOUNDS_OUTLINE_PROVIDER);
138     }
139 
setViewPager(ViewPager viewPager)140     public void setViewPager(ViewPager viewPager) {
141         mPager = viewPager;
142         addTabs(mPager.getAdapter());
143     }
144 
setTabIcons(int [] tabIcons)145     public void setTabIcons(int [] tabIcons) {
146         mTabIcons = tabIcons;
147     }
148 
addTabs(PagerAdapter adapter)149     private void addTabs(PagerAdapter adapter) {
150         mTabStrip.removeAllViews();
151 
152         final int count = adapter.getCount();
153         for (int i = 0; i < count; i++) {
154             addTab(adapter.getPageTitle(i), i);
155         }
156     }
157 
addTab(CharSequence tabTitle, final int position)158     private void addTab(CharSequence tabTitle, final int position) {
159         View tabView;
160         if (mTabIcons != null && position < mTabIcons.length) {
161             View iconView = new View(getContext());
162             iconView.setBackgroundResource(mTabIcons[position]);
163             iconView.setContentDescription(tabTitle);
164 
165             tabView = iconView;
166         } else {
167             final TextView textView = new TextView(getContext());
168             textView.setText(tabTitle);
169             textView.setBackgroundResource(R.drawable.view_pager_tab_background);
170 
171             // Assign various text appearance related attributes to child views.
172             if (mTextStyle > 0) {
173                 textView.setTypeface(textView.getTypeface(), mTextStyle);
174             }
175             if (mTextSize > 0) {
176                 textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
177             }
178             if (mTextColor != null) {
179                 textView.setTextColor(mTextColor);
180             }
181             textView.setAllCaps(mTextAllCaps);
182             textView.setGravity(Gravity.CENTER);
183 
184             tabView = textView;
185         }
186 
187         tabView.setOnClickListener(new OnClickListener() {
188             @Override
189             public void onClick(View v) {
190                 mPager.setCurrentItem(getRtlPosition(position));
191             }
192         });
193 
194         tabView.setOnLongClickListener(new OnTabLongClickListener(position));
195 
196         tabView.setPadding(mSidePadding, 0, mSidePadding, 0);
197         mTabStrip.addView(tabView, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
198                 LayoutParams.MATCH_PARENT, 1));
199 
200         // Default to the first child being selected
201         if (position == 0) {
202             mPrevSelected = 0;
203             tabView.setSelected(true);
204         }
205     }
206 
207     @Override
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)208     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
209         position = getRtlPosition(position);
210         int tabStripChildCount = mTabStrip.getChildCount();
211         if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
212             return;
213         }
214 
215         mTabStrip.onPageScrolled(position, positionOffset, positionOffsetPixels);
216     }
217 
218     @Override
onPageSelected(int position)219     public void onPageSelected(int position) {
220         position = getRtlPosition(position);
221         int tabStripChildCount = mTabStrip.getChildCount();
222         if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
223             return;
224         }
225 
226         if (mPrevSelected >= 0 && mPrevSelected < tabStripChildCount) {
227             mTabStrip.getChildAt(mPrevSelected).setSelected(false);
228         }
229         final View selectedChild = mTabStrip.getChildAt(position);
230         selectedChild.setSelected(true);
231 
232         // Update scroll position
233         final int scrollPos = selectedChild.getLeft() - (getWidth() - selectedChild.getWidth()) / 2;
234         smoothScrollTo(scrollPos, 0);
235         mPrevSelected = position;
236     }
237 
238     @Override
onPageScrollStateChanged(int state)239     public void onPageScrollStateChanged(int state) {
240     }
241 
getRtlPosition(int position)242     private int getRtlPosition(int position) {
243         if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
244             return mTabStrip.getChildCount() - 1 - position;
245         }
246         return position;
247     }
248 }
249 
250