您的位置:首页 > 移动开发 > Android开发

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

2016-03-15 14:07 706 查看
前言:

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

正文:



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

必要的安卓基础
安卓view 的执行流程
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);
}
}




其实我们移动的就是蓝色的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:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/demo"
>

<com.beyole.view.HightLightTextView
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dip"
android:textSize="22sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="滑动解锁" />

</RelativeLayout>


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

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

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

题外话:

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

新浪微博:SmartIceberg
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: