史上最简的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例子源码仿网易title新闻标题和内容滑动

  • 2017年01月11日 11:05
  • 1.24MB
  • 下载

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

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

ViewPagerIndicate的使用总结

1)在以Module和添加依赖的方式引用ViewPagerIndicate; 2)让使用ViewpagerIndicate的activity继承自FragmentActivity; 3)书写模板性代码...
  • chenrushui
  • chenrushui
  • 2016年05月13日 09:47
  • 910

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

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

boost asio异步读写网络聊天程序客户端 实例详解

boost开发文档中实时聊天程序的客户端(加入了详细注释 方便理解)
  • cyg0810
  • cyg0810
  • 2014年07月01日 10:52
  • 13273

ps切图(3)——简单工具操作(2)

八个常见的处理图片的工具
  • xiyoki
  • xiyoki
  • 2016年02月22日 18:48
  • 862

python 的日志logging模块学习

1.简单的将日志打印到屏幕   import logging logging.debug('This is debug message') logging.in...
  • a87b01c14
  • a87b01c14
  • 2015年05月18日 17:31
  • 1070

音视频的流程:录制、播放、编码解码、上传下载等

> 音视频的录制、播放、编码、上传、下载、观看等,视频编解码,音频编解码,线音频播放 音视频同步等 查看源码的工具:sourceinsight , 不了解JNI的一定要学习下,否则只能在JAVA层搞...
  • ShareUs
  • ShareUs
  • 2016年12月11日 14:37
  • 1184

图像傅里叶变换

转自:http://blog.csdn.net/u011630458/article/details/52503647?locationNum=7&fps=1 简介   本篇是对回顾图像傅里叶...
  • sinat_31337047
  • sinat_31337047
  • 2017年03月20日 17:34
  • 157

屏幕适配之尺寸的相关概论《一》

最近写了一个屏幕尺寸的教程,同时也弥补一下自己的基础。今天我们先来探讨一下项目尺寸的相关知识 屏幕及其屏幕的相关基本知识 android中dip、dp、px、sp和屏幕密度 屏幕尺寸很多人不知道屏幕尺...
  • androidstarjack
  • androidstarjack
  • 2017年12月28日 09:07
  • 59
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:史上最简的ViewPagerIndicate,高仿网易新闻客户端效果
举报原因:
原因补充:

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