史上最简的ViewPagerIndicate,高仿网易新闻客户端效果

原创 2016年08月25日 16:11:43

运行效果

在编写代码之前,先看看最终运行效果:


代码编写

首先自定义一个控件,名叫ViewPagerIndicate,继承HorizontalScrollView,实现View.OnClickListener接口监听,代码如下:
package com.example.viewpagerindicate.view;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class ViewPagerIndicate extends HorizontalScrollView implements OnClickListener {
	
	private Context mContext;
	private LayoutInflater mInflater;
	private ViewPager mViewPager;
	//onMeasure是否准备完成
	private boolean isMeasureOk;
	//是否可以绘制下划线
	private boolean isDrawOK;
	//HorizontalScrollView只能有1个子View(这里用线性布局)
	private LinearLayout mWapper;
	//标签
	private ArrayList<TextView> mTextViews;
	//标签正常颜色和高亮颜色
	private int mTextNormalColor, mTextHighlightColor;
	//总宽度
	private int mTotalWidth;
	//1个标签的宽和高
	private int mTabWidth, mTabHeight;  
	private Paint mPaint;
	//下划线的位置
	private float mTranslateX;
	
	public ViewPagerIndicate(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		mInflater = LayoutInflater.from(context);
		mPaint = new Paint();
		isMeasureOk = isDrawOK = false;
	}
	
	/**
	 * 重置下划线的粗细和颜色
	 * @param size 下划线粗细
	 * @param color 下划线颜色
	 */
	public void resetUnderline(int size, int color) {
		mPaint.setStrokeWidth((int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, size, mContext.getResources().getDisplayMetrics()));
		mPaint.setColor(color);
	}
	
	/**
	 * 重置标签的布局样式、标题和颜色
	 * @param tabId 布局样式id
	 * @param titles 标题集合
	 * @param colors 颜色集合
	 */
	public void resetText(int tabId, String[] titles, int[] colors) {
		mTextNormalColor = colors[0];
		mTextHighlightColor = colors[1];
		mTextViews = new ArrayList<TextView>();
		for (int i = 0; i < titles.length; i++) {
			TextView tv = (TextView) mInflater.inflate(tabId, null);
			tv.setText(titles[i]);
			tv.setTag(i);
			tv.setOnClickListener(this);
			mTextViews.add(tv);
		}
		setTextHighlight(0);
	}
	
	/**
	 * 高亮对应位置的标签颜色
	 * @param pos 对应位置
	 */
	private void setTextHighlight(int pos) {
		for (int i = 0; i < mTextViews.size(); i++) {
			if (i == pos)
				mTextViews.get(pos).setTextColor(mTextHighlightColor);
			else
				mTextViews.get(i).setTextColor(mTextNormalColor);
		}
	}
	
	/**
	 * 之所以设置此方法,主要是用于网络获取数据,而不是使用静态文本;
	 * 当网络请求成功,手动调用该方法完成初始化
	 */
	public void setOk() {
		isMeasureOk = true;
		isDrawOK = true;
		requestLayout();
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		//必须放在super.onMeasure的前面,否则后面无法获得子View的宽高
		if (isMeasureOk) {
			removeAllViews();
			mWapper = new LinearLayout(mContext);
			for (TextView tv : mTextViews) {
				mWapper.addView(tv);
			}
			addView(mWapper);
		}
		
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		
		if (isMeasureOk) {
			if (mTextViews.size() > 0) {
				mTotalWidth = getMeasuredWidth();
				TextView tv = (TextView) mWapper.getChildAt(0);
				mTabWidth = tv.getMeasuredWidth();
				mTabHeight = tv.getMeasuredHeight();
			}
			isMeasureOk = false;
		}
	}
	
	/**
	 * 设置下划线的位置
	 * @param pos ViewPager对应的索引位置
	 * @param posOffset ViewPager滑动百分比
	 */
	private void drawUnderline(int pos, float posOffset) {
		mTranslateX = pos * mTabWidth + posOffset * mTabWidth;
		invalidate();
	}
	
	/**
	 * 设置下划线的位置
	 * @param pos ViewPager对应的索引位置
	 */
	private void drawUnderline(int pos) {
		mTranslateX = pos * mTabWidth;
		invalidate();
	}
	
	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (isDrawOK) {
			//改变下划线的位置
			canvas.translate(mTranslateX, 0);
			//绘制下划线
			canvas.drawLine(0, mTabHeight, mTabWidth, mTabHeight, mPaint);
		}
	}
	
	/**
	 * 重置ViewPager
	 */
	public void resetViewPager(ViewPager viewPager) {
		mViewPager = viewPager;
		mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
			/*ViewPager某项被选中*/
			@Override
			public void onPageSelected(int position) {
				//高亮该项文字
				setTextHighlight(position);
			}
			
			/*ViewPager从某项滑动到另一项*/
			@Override
			public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
				drawUnderline(position, positionOffset);
				//实现标签与下划线一起滚动的效果
				scrollTo((int) ((position + positionOffset - 1) * mTabWidth), 0);
			}
			
			@Override
			public void onPageScrollStateChanged(int arg0) {}
		});
	}
	
	/**
	 * 标签点击事件监听
	 */
	@Override
	public void onClick(View v) {
		int pos = (Integer) v.getTag();
		//让当前标签总是显示在第二个位置
		smoothScrollTo((pos - 1) * mTabWidth, 0);
		drawUnderline(pos);
		mViewPager.setCurrentItem(pos, false);
	}
}
MainActivity代码如下:
package com.example.viewpagerindicate;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.viewpagerindicate.view.ViewPagerIndicate;

public class MainActivity extends Activity {
	private ViewPager mViewPager;
	private ViewPagerIndicate mIndicate;
	private int[] mTextColors = {0xFFA0A0A0, 0xFF000000};
	private int mUnderlineColor = 0xFF168EFF;
	private String[] mTitles = new String[] {
			"要闻", "奥运", "视频", "娱乐", "体育", "NBA",
			"财经", "汽车", "科技", "社会", "军事", "国际",
			"时尚", "文化", "游戏", "图片", "数码", "星座",
			"电影", "教育", "美容", "动漫", "理财", "民生"};
	private ArrayList<TextView> mTextViews;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initViewPgaer();
		initViewPagerIndicate();
	}
	
	private void initViewPgaer() {
		mTextViews = new ArrayList<TextView>();
		for (int i = 0; i < mTitles.length; i++) {
			TextView tv = new TextView(this);
			tv.setGravity(Gravity.CENTER);
			tv.setText(mTitles[i]);
			mTextViews.add(tv);
		}
		mViewPager = (ViewPager) findViewById(R.id.viewPager);
		mViewPager.setAdapter(new PagerAdapter() {
			@Override
			public Object instantiateItem(ViewGroup container, int position) {
				TextView tv = mTextViews.get(position);
				container.addView(tv);
				return tv;
			}
			
			@Override
			public void destroyItem(ViewGroup container, int position,
					Object object) {
				container.removeView(mTextViews.get(position));
			}
			
			@Override
			public boolean isViewFromObject(View arg0, Object arg1) {
				return arg0 == arg1;
			}
			
			@Override
			public int getCount() {
				return mTextViews.size();
			}
		});
	}
	
	private void initViewPagerIndicate() {
		mIndicate = (ViewPagerIndicate) findViewById(R.id.indicate);
		//设置标签样式、文本和颜色
		mIndicate.resetText(R.layout.layout_text_indicate, mTitles, mTextColors);
		//设置下划线粗细和颜色
		mIndicate.resetUnderline(4, mUnderlineColor);
		//设置ViewPager
		mIndicate.resetViewPager(mViewPager);
		//设置初始化完成
		mIndicate.setOk();
	}
}

编写布局

activity_main.xml代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFF"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFF"
        android:paddingLeft="10dp"
        android:paddingRight="10dp" >

        <com.example.viewpagerindicate.view.ViewPagerIndicate
            android:id="@+id/indicate"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="none" >
        </com.example.viewpagerindicate.view.ViewPagerIndicate>
    </LinearLayout>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginTop="2dp"
        android:background="#D5D5D5" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>
layout_text_indicate.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:paddingBottom="10dp"
    android:paddingTop="15dp"
    android:textSize="16sp" >

</TextView>


相关文章推荐

Android-ViewPagerIndicator简单集成

现在很多的应用页面都是由一个个的TAB组成的,我们可以用布局加事件监听实现tab ,只是这样的控制非常麻烦,而且有很多的开源项目可以实现这样的功能,我们今天就介绍一下ViewPagerIndicato...
  • dalancon
  • dalancon
  • 2014年12月03日 14:08
  • 32014

Android Studio引用GitHub上的库 viewPagerIndicater

在学习Tab时,想实现Tab好看,变想引用ViewPagerIndicater,引用中,尽管前人给出的指点很多,但是自己用的AS版本为1.4beta  ,以此能给同样需求的人做参考。 首先在stac...
  • sangsa
  • sangsa
  • 2015年10月24日 11:31
  • 1023

自定义ViewPager的指示条---Indicate

自定义ViewPager的指示条—Indicate ONE Goal,ONE Passion! 好久都没有写东西了,5-1公司组织去重渡沟,风景真心不怎样.不过还是挺值得回忆的. 当想使用vi...

Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (Fragment ViewPager)

第二种主界面风格则是以网易新闻、凤凰新闻以及新推出的新浪博客(阅读版)为代表,使用ViewPager+Fragment,即ViewPager里适配器里放的不是一般的View,而是Fragment。所以...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

自定义等长的 ViewPagerIndicater

今天遇到的需求是让TAB的指示器的宽度,与TAB中文本 的宽度一致,看来部分源码之后,决定以这种形式来实现自己的项目需求。。。 先定义一些相关的变量 private float measure...
  • Ivenes
  • Ivenes
  • 2017年06月10日 16:26
  • 113

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

(android高仿系列)今日头条 --新闻阅读器 (一)

在模仿中循序渐进,以程序员角度去看待每一个APP是如何实现的,它有什么优缺点,并从中提升自己。        之前发现很多人在群里面、论坛上求网易新闻客户端的源码,之后我就去下了个网易新闻客户端和今日...

自定义指示条

直接上代码 package com.uwatch.uwpedometer.view; import android.content.Context; import android.gra...

ViewPagerIndicate的使用总结

1)在以Module和添加依赖的方式引用ViewPagerIndicate; 2)让使用ViewpagerIndicate的activity继承自FragmentActivity; 3)书写模板性代码...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:史上最简的ViewPagerIndicate,高仿网易新闻客户端效果
举报原因:
原因补充:

(最多只允许输入30个字)