Indicator确实是个老梗了...

有重写HorizontalScrollView的,有重写LinearLayout。

这个是重写LinearLayout的哦,往LinearLayout里add   TextView用作tab标签,在LinearLayout底部画一个矩形当作指示器。

ViewPager滚动的时候用简单的小学加减乘除混合运算来机选这个矩形位置,然后滚动就好了

android dig命令详解 android indicator_ide


属性



[html] 

1. <?xml version="1.0" encoding="utf-8"?>  
2. <resources>  
3.   
4. <attr name="tab_color_normal" format="color" />  
5. <attr name="tab_color_light" format="color" />  
6. <attr name="cursor_color" format="color" />  
7. <attr name="cursor_height" format="dimension" />  
8.   
9. <declare-styleable name="Indicator">  
10. <attr name="tab_color_normal" />  
11. <attr name="tab_color_light" />  
12. <attr name="cursor_color" />  
13. <attr name="cursor_height" />  
14. </declare-styleable>  
15.   
16. </resources>

Indicator.java  关键的地方都谢了注释

[java] 

1. package com.mingwei.indicator.view;  
2.   
3. import java.util.List;  
4.   
5. import android.annotation.TargetApi;  
6. import android.content.Context;  
7. import android.content.res.TypedArray;  
8. import android.graphics.Canvas;  
9. import android.graphics.Color;  
10. import android.graphics.Paint;  
11. import android.graphics.Paint.Style;  
12. import android.graphics.Rect;  
13. import android.os.Build;  
14. import android.support.v4.view.ViewPager;  
15. import android.support.v4.view.ViewPager.OnPageChangeListener;  
16. import android.util.AttributeSet;  
17. import android.util.TypedValue;  
18. import android.view.Gravity;  
19. import android.view.View;  
20. import android.view.View.OnClickListener;  
21. import android.widget.HorizontalScrollView;  
22. import android.widget.LinearLayout;  
23. import android.widget.TextView;  
24.   
25. import com.mingwei.indicator.R;  
26.   
27. @TargetApi(Build.VERSION_CODES.HONEYCOMB)  
28. public class Indicator extends LinearLayout implements OnClickListener, OnPageChangeListener {  
29. /**
30.      * 绘制时用的画笔
31.      */  
32. private Paint mPaint;  
33. /**
34.      * 默认颜色
35.      */  
36. private int mCursorColor;  
37. /**
38.      * 滚动的指示器的矩形范围
39.      */  
40. private Rect mRect = new Rect();  
41. /**
42.      * 滚动游标的绘制范围
43.      */  
44. private int mL, mR, mT, mB;  
45. /**
46.      * 最多可见的游标数
47.      */  
48. private int mVisiableTabCount = 4;  
49. /**
50.      * 游标高度
51.      */  
52. private int mCursorHeight = 6;  
53. /**
54.      * tab的宽度
55.      */  
56. private int mTabWidth;  
57. /**
58.      * 选中和非选中状态的标签文字颜色
59.      */  
60. private int mTabColorNormal;  
61. private int mTabColorLight;  
62. /**
63.      * 水平滚动的距离
64.      */  
65. private float mTranslationX;  
66. /**
67.      * 需要监听ViewPager动作来跟新游标
68.      */  
69. private ViewPager mViewPager;  
70.   
71. public Indicator(Context context) {  
72. this(context, null);  
73.     }  
74.   
75. public Indicator(Context context, AttributeSet attrs) {  
76. this(context, attrs, 0);  
77.     }  
78.   
79. public Indicator(Context context, AttributeSet attrs, int defStyleAttr) {  
80. super(context, attrs, defStyleAttr);  
81.         initAttr(context, attrs, defStyleAttr);  
82. new Paint();  
83.         mPaint.setColor(mCursorColor);  
84. true);  
85.         mPaint.setStyle(Style.FILL);  
86.     }  
87.   
88. private void initAttr(Context context, AttributeSet attrs, int defStyleAttr) {  
89.         TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Indicator);  
90.         mTabColorNormal = array.getColor(R.styleable.Indicator_tab_color_normal, Color.BLACK);  
91.         mTabColorLight = array.getColor(R.styleable.Indicator_tab_color_light, Color.WHITE);  
92.         mCursorColor = array.getColor(R.styleable.Indicator_cursor_color, Color.BLACK);  
93.         mCursorHeight = array.getDimensionPixelSize(R.styleable.Indicator_cursor_height, mCursorHeight);  
94.         array.recycle();  
95.     }  
96.   
97. @Override  
98. protected void onFinishInflate() {  
99. super.onFinishInflate();  
100.     }  
101.   
102. @Override  
103. protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
104. super.onSizeChanged(w, h, oldw, oldh);  
105.           
106. int count = getChildCount();  
107. if (count == 0) {  
108. return;  
109.         }  
110.         mTabWidth = getWidth() / mVisiableTabCount;  
111. for (int i = 0; i < count; i++) {  
112.             View view = getChildAt(i);  
113.             LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();  
114. 0;  
115.             params.width = mTabWidth;  
116.             params.height = getHeight() - mCursorHeight;  
117.             view.setLayoutParams(params);  
118.         }  
119. 0;  
120.         mT = getHeight() - mCursorHeight;  
121.         mR = mTabWidth;  
122.         mB = getHeight();  
123. new Rect(mL, mT, mR, mB);  
124.     }  
125.   
126. @Override  
127. protected void dispatchDraw(Canvas canvas) {  
128. super.dispatchDraw(canvas);  
129.         canvas.save();  
130. 0);  
131.         canvas.drawRect(mRect, mPaint);  
132.         canvas.restore();  
133.   
134.     }  
135.   
136. private void scroll(int position, float offset) {  
137.         mTranslationX = getWidth() / mVisiableTabCount * (position + offset);  
138. /**
139.          * 当tab数大于可见数目的时候,整个容器滚动
140.          */  
141. if (getChildCount() > mVisiableTabCount && offset > 0 && (position >= mVisiableTabCount - 2)) {  
142. if (mVisiableTabCount != 1) {  
143. /**
144.                  * 当tab等于可见数目不是倒数第二个时滚动容器,否则仍然滚动游标
145.                  */  
146. if (position != getChildCount() - 2) {  
147. 2)) * mTabWidth + (int) (offset * mTabWidth), 0);  
148.                 }  
149. else {  
150. int) (offset * mTabWidth), 0);  
151.             }  
152.         }  
153.         invalidate();  
154.   
155.     }  
156.   
157. public void setViewPager(ViewPager viewPager) {  
158.         mViewPager = viewPager;  
159. this);  
160.     }  
161.   
162. public void setTabs(String[] tabs) {  
163.         removeAllViews();  
164. for (String t : tabs) {  
165.             createChild(t);  
166.         }  
167. 0);  
168.         view.setTextColor(mTabColorLight);  
169.     }  
170.   
171. public void setTabs(List<String> tabs) {  
172.         removeAllViews();  
173. for (String t : tabs) {  
174.             createChild(t);  
175.         }  
176. 0);  
177.         view.setTextColor(mTabColorLight);  
178.     }  
179.   
180. private void setTabLight(int arg0) {  
181. int count = getChildCount();  
182. for (int i = 0; i < count; i++) {  
183.             TextView view = (TextView) getChildAt(i);  
184. if (i == arg0) {  
185.                 view.setTextColor(mTabColorLight);  
186. else {  
187.                 view.setTextColor(mTabColorNormal);  
188.             }  
189.         }  
190.     }  
191.   
192. /**
193.      * 创建子View
194.      * 
195.      * @param text
196.      */  
197. private void createChild(String text) {  
198. new TextView(getContext());  
199.         view.setText(text);  
200.         view.setGravity(Gravity.CENTER);  
201.         view.setTextColor(mTabColorNormal);  
202. 16);  
203. this);  
204.         view.setTag(getChildCount());  
205.         addView(view);  
206.     }  
207.   
208. @Override  
209. public void onPageScrollStateChanged(int arg0) {  
210.   
211.     }  
212.   
213. @Override  
214. public void onPageScrolled(int arg0, float arg1, int arg2) {  
215.         scroll(arg0, arg1);  
216.     }  
217.   
218. @Override  
219. public void onPageSelected(int arg0) {  
220.         setTabLight(arg0);  
221.     }  
222.   
223. @Override  
224. public void onClick(View arg0) {  
225. int i = (Integer) arg0.getTag();  
226.         mViewPager.setCurrentItem(i);  
227.     }  
228.   
229. }



XML使用

[html] 

1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
2. xmlns:tools="http://schemas.android.com/tools"  
3. android:layout_width="match_parent"  
4. android:layout_height="match_parent"  
5. android:orientation="vertical" >  
6.   
7. <com.mingwei.indicator.view.Indicator  
8. xmlns:ming="http://schemas.android.com/apk/res-auto"  
9. android:id="@+id/indicator"  
10. android:layout_width="match_parent"  
11. android:layout_height="45dp"  
12. android:orientation="horizontal"  
13. ming:cursor_color="@color/indicator_color"  
14. ming:cursor_height="3dp"  
15. ming:tab_color_light="@color/tab_color_checked"  
16. ming:tab_color_normal="@color/tab_color_normal" >  
17. </com.mingwei.indicator.view.Indicator>  
18.   
19. <android.support.v4.view.ViewPager  
20. android:id="@+id/viewpager"  
21. android:layout_width="match_parent"  
22. android:layout_height="match_parent" >  
23. </android.support.v4.view.ViewPager>  
24.   
25. </LinearLayout>



MainActivity

[java] 

1. package com.mingwei.indicator;  
2.   
3. import java.util.ArrayList;  
4. import java.util.Arrays;  
5. import java.util.List;  
6.   
7. import android.os.Bundle;  
8. import android.support.v4.app.Fragment;  
9. import android.support.v4.app.FragmentActivity;  
10. import android.support.v4.app.FragmentPagerAdapter;  
11. import android.support.v4.view.ViewPager;  
12. import android.view.Menu;  
13. import android.view.MenuItem;  
14.   
15. import com.mingwei.indicator.view.Indicator;  
16.   
17. public class MainActivity extends FragmentActivity {  
18.   
19. private ViewPager mViewPager;  
20.   
21. private List<Fragment> mFragments = new ArrayList<Fragment>();  
22.   
23. private FragmentPagerAdapter mAdapter;  
24.   
25. private List<String> mStrings = Arrays.asList("标签1", "标签2", "标签3", "标签4", "标签5");  
26.   
27. private Indicator mIndicator;  
28.   
29. @Override  
30. protected void onCreate(Bundle savedInstanceState) {  
31. super.onCreate(savedInstanceState);  
32.         setContentView(R.layout.activity_main);  
33.         initView();  
34.     }  
35.   
36. private void initView() {  
37.   
38. for (String tabs : mStrings) {  
39.             SimpleFragment fragment = SimpleFragment.newInstance(tabs);  
40.             mFragments.add(fragment);  
41.         }  
42.         mViewPager = (ViewPager) findViewById(R.id.viewpager);  
43.         mIndicator = (Indicator) findViewById(R.id.indicator);  
44.         mIndicator.setTabs(mStrings);  
45.         mIndicator.setViewPager(mViewPager);  
46. new FragmentPagerAdapter(getSupportFragmentManager()) {  
47.   
48. @Override  
49. public int getCount() {  
50. return mFragments.size();  
51.             }  
52.   
53. @Override  
54. public Fragment getItem(int position) {  
55. return mFragments.get(position);  
56.             }  
57.         };  
58.         mViewPager.setAdapter(mAdapter);  
59.   
60.     }  
61.   
62. @Override  
63. public boolean onCreateOptionsMenu(Menu menu) {  
64. // Inflate the menu; this adds items to the action bar if it is present.  
65.         getMenuInflater().inflate(R.menu.main, menu);  
66. return true;  
67.     }  
68.   
69. @Override  
70. public boolean onOptionsItemSelected(MenuItem item) {  
71. // Handle action bar item clicks here. The action bar will  
72. // automatically handle clicks on the Home/Up button, so long  
73. // as you specify a parent activity in AndroidManifest.xml.  
74. int id = item.getItemId();  
75. if (id == R.id.action_settings) {  
76. return true;  
77.         }  
78. return super.onOptionsItemSelected(item);  
79.     }  
80. }