Android自定义view-打造酷炫的字体滑动高亮控件

前言:

相信很多时候开发会遇到类似于音乐歌词同步,播放到哪句歌词的哪个词时会逐渐高亮,这样的描述还是不够准确,iPhone的滑动解锁的那种效果,相信很多人都会熟悉吧。今天,我们的首要任务就是开发一个类似于这种效果的安卓控件,以便在以后的项目中直接使用,看起来高大上有木有。其实也不用害怕,需要我们分析和撰写的内容并不多,废话不多说,开始我们今天的教程吧。

正文:

Android自定义view-打造酷炫的字体滑动高亮控件_第1张图片

在开始讲解之前,需要准备的知识点有:

  1. 必要的安卓基础
  2. 安卓view 的执行流程
  3. Android画笔的LinearGradient线性渲染
好了,其实对于以上知识点不了解也没有关系,要是都了解了,就没有必要写这篇文章了。

问题一:为什么要有必要的安卓基础呢?
如果对继承,重写组件没有必要的了解,这篇文章是看不下去的。

问题二:安卓的view执行流程是什么呢?
  • 执行构造方法
  • onFinishInflate
  • onSizeChanged
  • onDraw
  • ....
问题三:LinearGradient的线性渲染需要了解哪些内容呢?
LinearGradient有两个构造函数:
public LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions,Shader.TileMode tile) 
参数:
float x0: 渐变起始点x坐标
float y0:渐变起始点y坐标
float x1:渐变结束点x坐标
float y1:渐变结束点y坐标
int[] colors:颜色 的int 数组
float[] positions: 相对位置的颜色数组,可为null,  若为null,可为null,颜色沿渐变线均匀分布
Shader.TileMode tile: 渲染器平铺模式


public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,Shader.TileMode tile)
float x0: 渐变起始点x坐标
float y0:渐变起始点y坐标
float x1:渐变结束点x坐标
float y1:渐变结束点y坐标
int color0: 起始渐变色
int color1: 结束渐变色
Shader.TileMode tile: 渲染器平铺模式

Shader.TileMode有3种参数可供选择,分别为CLAMP、REPEAT和MIRROR:

CLAMP的作用是如果渲染器超出原始边界范围,则会复制边缘颜色对超出范围的区域进行着色
REPEAT的作用是在横向和纵向上以平铺的形式重复渲染位图
MIRROR的作用是在横向和纵向上以镜像的方式重复渲染位图

知识准备已经完成了,开始动手撸代码了。

Step1:继承TextView
public class HightLightTextView extends TextView 

Step2:重写三个构造方法,当然根据需要,重写一个两个参数的构造方法也行。我复写三个是为了以后能够使用自定义属性。
	// 构造方法
	public HightLightTextView(Context context) {
		this(context, null);
	}

	public HightLightTextView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public HightLightTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

Step3:在onSizeChanged方法中初始化参数。
/**
	 * view的调用过程:构造方法->onFinishInflate->onSizeChanged->onDraw
	 */
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		// 获取view的宽度,初始化画笔等初始属性
		if (mTextViewWidth == 0) {
			mTextViewWidth = getMeasuredWidth();
			// 如果宽度大于0的话,则初始化
			if (mTextViewWidth > 0) {
				// 初始化画笔
				mPaint = getPaint();
				// 线性渲染
				mLinearGradient = new LinearGradient(-mTextViewWidth, 0, 0, 0, new int[] { 0X55FFFFFF, 0XFFFFFFFF, 0X55FFFFFF }, new float[] { 0, 0.5f, 1 }, TileMode.CLAMP);
				mPaint.setShader(mLinearGradient);
				matrix = new Matrix();
			}
		}
	}

这里有个细节,就是画笔的获取,我们不是new出来的,而是通过getPaint()获取父类中的画笔,所以接下来的onDraw中没有用到paint,不要怀疑代码有问题哦。
至于LinearGradient的每个参数对照我们的知识准备应该不难理解各种参数对应的意思。那么,还剩下一个问题,这里的mTextViewWidth为什么是负的,喏,其实我们的matrix的移动是从-mTextViewWidth<=translate<=mTextViewWidth,可能还是不能理解吧。我们到下面画个图解释一下就清楚了。

Step4:在onDraw中绘制view
@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (isAnimateOn && matrix != null) {
			mTranslateX += mTextViewWidth / 10;
			// 如果移动的距离大于两倍的宽度,则重新开始移动
			if (mTranslateX > 2 * mTextViewWidth) {
				mTranslateX = -mTextViewWidth;
			}
			// 平移matrix
			matrix.setTranslate(mTranslateX, 0);
			// 设置线性变化的matrix
			mLinearGradient.setLocalMatrix(matrix);
			// 延迟100ms重绘
			postInvalidateDelayed(100);
		}
	}

Android自定义view-打造酷炫的字体滑动高亮控件_第2张图片
其实我们移动的就是蓝色的matrix,移动了两倍的textview之后,再重置matrix,然后就postInvalidateDelayed绘制我们的view。okay了,看到这里应该很熟悉怎么去写这样的一个效果了吧。如果你觉得滑动慢,改变一些重绘的时间,如果你觉得颜色需要改变,那就设置对外的接口,或者直接修改view里的颜色即可,至于扩展,留给大家扩展了。

这里贴上view 的全部代码以及如何使用:

HightLightTextView.java
package com.beyole.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader.TileMode;
import android.util.AttributeSet;
import android.widget.TextView;

public class HightLightTextView extends TextView {

	// 存储view的宽度
	private int mTextViewWidth = 0;
	// 画笔
	private Paint mPaint;
	// 线性渲染
	private LinearGradient mLinearGradient;
	// 存储变换的matrix
	private Matrix matrix;
	// 移动距离
	private int mTranslateX = 0;
	// 是否开启动画
	private boolean isAnimateOn = true;

	// 构造方法
	public HightLightTextView(Context context) {
		this(context, null);
	}

	public HightLightTextView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public HightLightTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	/**
	 * view的调用过程:构造方法->onFinishInflate->onSizeChanged->onDraw
	 */
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		// 获取view的宽度,初始化画笔等初始属性
		if (mTextViewWidth == 0) {
			mTextViewWidth = getMeasuredWidth();
			// 如果宽度大于0的话,则初始化
			if (mTextViewWidth > 0) {
				// 初始化画笔
				mPaint = getPaint();
				// 线性渲染
				mLinearGradient = new LinearGradient(-mTextViewWidth, 0, 0, 0, new int[] { 0X55FFFFFF, 0XFFFFFFFF, 0X55FFFFFF }, new float[] { 0, 0.5f, 1 }, TileMode.CLAMP);
				mPaint.setShader(mLinearGradient);
				matrix = new Matrix();
			}
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (isAnimateOn && matrix != null) {
			mTranslateX += mTextViewWidth / 10;
			// 如果移动的距离大于两倍的宽度,则重新开始移动
			if (mTranslateX > 2 * mTextViewWidth) {
				mTranslateX = -mTextViewWidth;
			}
			// 平移matrix
			matrix.setTranslate(mTranslateX, 0);
			// 设置线性变化的matrix
			mLinearGradient.setLocalMatrix(matrix);
			// 延迟100ms重绘
			postInvalidateDelayed(100);
		}
	}

}

activity_main.xml:


    



好了,教程到此为止结束了。

下载地址:http://download.csdn.net/detail/smarticeberg/9462069

Github地址:https://github.com/xuejiawei/beyole_highlighttextview,欢迎fork or star


题外话:

android交流群:279031247(广告勿入)

新浪微博:SmartIceberg








你可能感兴趣的:(Android自定义view)