史上最简的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:23
  • 32996

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

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

Android Studio引用GitHub上的库 viewPagerIndicater

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

安卓开发中非常炫的效果集合

这几天开发的时候,想做一些好看而且酷炫的特效,于是又开始从网上收集各种特效资源。下面给大家一些我喜欢的把,附代码,喜欢的看源代码,然后加到自己项目去把!! 1.很简单却很酷的粒子破碎效果 介...
  • easyer2012
  • easyer2012
  • 2016-01-08 16:34:32
  • 28312

Android 开源框架ViewPageIndicator 和 ViewPager 仿网易新闻客户端Tab标签

之前用JakeWharton的开源框架ActionBarSherlock和ViewPager实现了对网易新闻客户端Tab标签的功能,ActionBarSherlock是在3.0以下的机器支持Actio...
  • xiaanming
  • xiaanming
  • 2013-09-01 11:32:30
  • 161951

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

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

高仿网易新闻客户端最终版Android应用源码下载

  • 2017年02月16日 11:16
  • 6.46MB
  • 下载

Android应用源码高仿网易新闻客户端最终版

  • 2016年05月21日 00:27
  • 6.46MB
  • 下载

(android高仿系列)今日头条 --新闻阅读器 (三) 完结 、总结 篇

从写第一篇今日头条高仿系列开始,到现在已经过去了1个多月了,其实大体都做好了,就是迟迟没有放出来,因为我觉得,做这个东西也是有个过程的,我想把这个模仿中一步一步学习的过程,按照自己的思路写下来,在根据...
  • vipzjyno1
  • vipzjyno1
  • 2014-05-22 00:09:38
  • 65649

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

在模仿中循序渐进,以程序员角度去看待每一个APP是如何实现的,它有什么优缺点,并从中提升自己。        之前发现很多人在群里面、论坛上求网易新闻客户端的源码,之后我就去下了个网易新闻客户端和今日...
  • vipzjyno1
  • vipzjyno1
  • 2014-04-13 13:10:50
  • 44874
收藏助手
不良信息举报
您举报文章:史上最简的ViewPagerIndicate,高仿网易新闻客户端效果
举报原因:
原因补充:

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