Android自定义View绘图实现渐隐动画

本文实现了一个有趣的小东西:使用自定义View绘图,一边画线,画出的线条渐渐变淡,直到消失。效果如下图所示:

用属性动画或者渐变填充(Shader)可以做到一笔一笔的变化,但要想一笔渐变(手指不抬起边画边渐隐),没在Android中找到现成的API可用。所以,自己做了一个。

基本的想法是这样的:

•在View的onTouchEvent中记录触摸点,生成一条一条的线LineElement,放在一个List中。给每个LineElement配置一个Paint实例。

•在onDraw中绘制线段。

•变换LineElement的Paint实例的Alpha值。

•根据Alpha值重组线段列表 

别的不说了,上代码:

package com.example.disappearinglines;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.RectF;

import android.os.Handler;

import android.os.Message;

import android.os.SystemClock;

import android.support.annotation.NonNull;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import java.util.ArrayList;

import java.util.Collection;

import java.util.Iterator;

import java.util.List;

import java.util.ListIterator;

public class DisappearingDoodleView extends View {

final static String TAG = "DoodleView";

class LineElement {

static final public int ALPHA_STEP = 5;

static final public int SUBPATH_DIMENSION = 8;

public LineElement(){

mPaint = new Paint();

mPaint.setARGB(255, 255, 0, 0);

mPaint.setAntiAlias(true);

mPaint.setStrokeWidth(16);

mPaint.setStrokeCap(Paint.Cap.BUTT);

mPaint.setStyle(Paint.Style.STROKE);

}

public LineElement(Paint paint){

mPaint = paint;

}

public void setPaint(Paint paint){

mPaint = paint;

}

public void setAlpha(int alpha){

mPaint.setAlpha(alpha);

}

public float mStartX = -1;

public float mStartY = -1;

public float mEndX = -1;

public float mEndY = -1;

public Paint mPaint;

}

private LineElement mCurrentLine = null;

private List<LineElement> mLines = null;

private long mElapsed = 0;

private Handler mHandler = new Handler(){

@Override

public void handleMessage(Message msg){

DisappearingDoodleView.this.invalidate();

}

};

public DisappearingDoodleView(Context context){

super(context);

}

public DisappearingDoodleView(Context context, AttributeSet attrs){

super(context, attrs);

}

@Override

protected void onDraw(Canvas canvas){

mElapsed = SystemClock.elapsedRealtime();

if(mLines != null) {

for (LineElement e : mLines) {

if(e.mStartX < 0 || e.mEndY < 0) continue;

canvas.drawLine(e.mStartX, e.mStartY, e.mEndX, e.mEndY, e.mPaint);

}

compactPaths();

}

}

@Override

public boolean onTouchEvent(MotionEvent event){

float x = event.getX();

float y = event.getY();

int action = event.getAction();

if(action == MotionEvent.ACTION_UP){// end one line after finger release

mCurrentLine.mEndX = x;

mCurrentLine.mEndY = y;

mCurrentLine = null;

invalidate();

return true;

}

if(action == MotionEvent.ACTION_DOWN){

mCurrentLine = new LineElement();

addToPaths(mCurrentLine);

mCurrentLine.mStartX = x;

mCurrentLine.mStartY = y;

return true;

}

if(action == MotionEvent.ACTION_MOVE) {

mCurrentLine.mEndX = x;

mCurrentLine.mEndY = y;

mCurrentLine = new LineElement();

addToPaths(mCurrentLine);

mCurrentLine.mStartX = x;

mCurrentLine.mStartY = y;

}

if(mHandler.hasMessages(1)){

mHandler.removeMessages(1);

}

Message msg = new Message();

msg.what = 1;

mHandler.sendMessageDelayed(msg, 0);

return true;

}

private void addToPaths(LineElement element){

if(mLines == null) {

mLines = new ArrayList<LineElement>() ;

}

mLines.add(element);

}

public void compactPaths(){

int size = mLines.size();

int index = size - 1;

if(size == 0) return;

int baseAlpha = 255 - LineElement.ALPHA_STEP;

int itselfAlpha;

LineElement line;

for(; index >=0 ; index--, baseAlpha -= LineElement.ALPHA_STEP){

line = mLines.get(index);

itselfAlpha = line.mPaint.getAlpha();

if(itselfAlpha == 255){

if(baseAlpha <= 0){

++index;

break;

}

line.setAlpha(baseAlpha);

}else{

itselfAlpha -= LineElement.ALPHA_STEP;

if(itselfAlpha <= 0){

++index;

break;

}

line.setAlpha(itselfAlpha);

}

}

if(index >= size){

// all sub-path should disappear

mLines = null;

}

else if(index >= 0){

//Log.i(TAG, "compactPaths from " + index + " to " + (size - 1));

mLines = mLines.subList(index, size);

}else{

// no sub-path should disappear

}

long interval = 40 - SystemClock.elapsedRealtime() + mElapsed;

if(interval < 0) interval = 0;

Message msg = new Message();

msg.what = 1;

mHandler.sendMessageDelayed(msg, interval);

}

}

这个示例还可以添加一些效果,比如让线条一边变淡一边变细。

目前还有一些问题,线条粗的话,可以明显看到线段与线段之间有缝隙或裂口,哪位想到怎么优化?

以上是 Android自定义View绘图实现渐隐动画 的全部内容, 来源链接: utcz.com/z/314534.html

回到顶部