Android换页指示器TabIndicator

来源:互联网 发布:淘宝天猫优惠券采集 编辑:程序博客网 时间:2024/06/06 08:03

一、看效果




二、实现原理

1、继承线性布局LinearLayout;

2、在测量方法onMeasure中,在原高度上基础上增加下划线高度:

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + underlineHeight);}


3、在布局方法onLayout中,为下划线预留高度:

@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b - underlineHeight);}


4、在绘制方法onDraw中,绘制下划线:

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int childCount = getChildCount();if (childCount <= 0 || currentTab < 0 || currentTab >= childCount) {return;}if (offset < -1) {offset = -1;}if (offset > 1) {offset = 1;}View child = getChildAt(currentTab);int underlineWidth = child.getWidth();int left = child.getLeft();int right = child.getRight();int bottom = getHeight() - getPaddingBottom();int top = bottom - underlineHeight;float offsetWidth = underlineWidth * offset;paint.setColor(underlineColor);canvas.drawRect(left + offsetWidth, top, right + offsetWidth, bottom, paint);}

注意,绘制方法中同时也实现下划线动态偏移的效果,后面可以看完整代码。


三、完整代码

在下述代码中,我们还给出了一个简单设置文本标签的快捷适配器。

import android.content.Context;import android.database.DataSetObserver;import android.graphics.Canvas;import android.graphics.Paint;import android.util.AttributeSet;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.LinearLayout;import android.widget.TextView;public class TabIndicator extends LinearLayout {protected BaseAdapter adapter;private int underlineColor;private int underlineHeight;private Paint paint;private int currentTab = 0;private float offset = 0;public TabIndicator(Context context) {this(context, null);}public TabIndicator(Context context, AttributeSet attrs) {super(context, attrs);initView();}public void setUnderlineColor(int underlineColor) {this.underlineColor = underlineColor;}public void setUnderlineHeight(int underlineHeight) {this.underlineHeight = underlineHeight;}public void setCurrentTab(int currentTab) {setCurrentTab(currentTab, 0);}public void setCurrentTab(int currentTab, float offset) {this.currentTab = currentTab;this.offset = offset;invalidate();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight() + underlineHeight);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b - underlineHeight);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int childCount = getChildCount();if (childCount <= 0 || currentTab < 0 || currentTab >= childCount) {return;}if (offset < -1) {offset = -1;}if (offset > 1) {offset = 1;}View child = getChildAt(currentTab);int underlineWidth = child.getWidth();int left = child.getLeft();int right = child.getRight();int bottom = getHeight() - getPaddingBottom();int top = bottom - underlineHeight;float offsetWidth = underlineWidth * offset;paint.setColor(underlineColor);canvas.drawRect(left + offsetWidth, top, right + offsetWidth, bottom, paint);}private void initView() {setOrientation(LinearLayout.HORIZONTAL);paint = new Paint();paint.setAntiAlias(true);}public void setAdapter(BaseAdapter adapter) {this.adapter = adapter;if (this.adapter == null) {removeAllViews();return;}this.adapter.registerDataSetObserver(new DataSetObserver() {@Overridepublic void onChanged() {fillChilds();}@Overridepublic void onInvalidated() {fillChilds();}});fillChilds();}protected void fillChilds() {removeAllViews();for (int i = 0; i < adapter.getCount(); i++) {final View child = adapter.getView(i, null, null);LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);params.gravity = Gravity.CENTER_VERTICAL;params.weight=1;addView(child, params);}}public static abstract class TextAdapter extends BaseAdapter {private final String[] titles;public TextAdapter(String[] titles) {this.titles = titles;}@Overridepublic int getCount() {if (titles == null || titles.length <= 0) {return 0;}return titles.length;}@Overridepublic Object getItem(int position) {if (titles == null || titles.length <= 0) {return null;}return titles[position];}@Overridepublic long getItemId(int position) {return position;}public abstract TextView getTextView(int position, View convertView, ViewGroup container);@Overridepublic View getView(final int position, View convertView, ViewGroup container) {TextView tv= getTextView(position, convertView, container);tv.setText(titles[position]);return tv;}}}


四、与ViewPager结合使用例子

TabIndicator tab = (TabIndicator) findViewById(R.id.tab);//设置下划线颜色tab.setUnderlineColor(Color.parseColor("#FFF44D06"));//设置下划线高度tab.setUnderlineHeight(6);//设置标签视图适配器tab.setAdapter(new TextAdapter(new String[]{"销量","价格","筛选"}) {@Overridepublic TextView getTextView(int position, View convertView, ViewGroup container) {return new TextView(getApplicationContext());}});ViewPager pager = (ViewPager) findViewById(R.id.pager);pager.setOnPageChangeListener(new OnPageChangeListener() {@Overridepublic void onPageSelected(int arg0) {}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {//注意,此处是让下划线动态滑动的关键tab.setCurrentTab(arg0, arg1);}@Overridepublic void onPageScrollStateChanged(int arg0) {}});

五、特性总结

1、指示器继承线性布局的一切原有特性和语义,无任何负作用;

2、指示器完全在布局层实现,与标签视图无关,适配器中的视图可以是任意View;

3、代码量精简,使用方便,性能稳定。


国际惯例

————————————————————————————————————————————————————————

作者:薄荷记账  (转载请注明原作者)

简洁   稳定   优雅   无限可能!

0 0