Android绘图之渐隐动画
实现了一个有趣的小东西:使用自定义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绘图之渐隐动画的更多相关文章
- Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧
第六章 Android绘图机制与处理技巧 1.屏幕尺寸信息屏幕大小:屏幕对角线长度,单位“寸”:分辨率:手机屏幕像素点个数,例如720x1280分辨率:PPI(Pixels Per Inch):即DP ...
- Android绘图机制(四)——使用HelloCharts开源框架搭建一系列炫酷图表,柱形图,折线图,饼状图和动画特效,抽丝剥茧带你认识图表之美
Android绘图机制(四)--使用HelloCharts开源框架搭建一系列炫酷图表,柱形图,折线图,饼状图和动画特效,抽丝剥茧带你认识图表之美 这里为什么不继续把自定义View写下去呢,因为最近项目 ...
- 第三章 Android绘图机制与处理技巧
1.屏幕尺寸信息 屏幕大小:屏幕对角线长度,单位“寸”:分辨率:手机屏幕像素点个数,例如720x1280分辨率:PPI(Pixels Per Inch):即DPI(Dots Per Inch),它是对 ...
- Android View的滑动 动画
[scrollTo/scrollBy] //控件内的文字会移动,但是控件本身不会移动,而且移动到控件之外之后,文字也就看不见了 if(v.equals(button2)){ button2.scrol ...
- Android之滑屏动画和自定义控件
滑屏动画 在Android系统中,通过手势识别切换界面时,通常会在界面切换时加入动画,以提高用户的体验效果,这种动画一般都采用平移动画,下一个界面进入时,上一个界面移除屏幕. 图中标识的均为左上角坐标 ...
- 论文第5章:Android绘图平台的实现
面向移动设备的矢量绘图平台设计与实现 Design and Implementation of Mobile Device-oriented Vector Drawing Platform 引用本论文 ...
- android 绘图之Canvas,Paint类
Canvas,Paint 1.在android 绘图但中经常要用到Canvas和Paint类,Canvas好比是一张画布,上面已经有你想绘制图画的轮廓了,而Paint就好比是画笔,就要给Canvas进 ...
- android中设置Animation 动画效果
在 Android 中, Animation 动画效果的实现可以通过两种方式进行实现,一种是 tweened animation 渐变动画,另一种是 frame by frame animation ...
- Android使用XML做动画UI
在Android应用程序,使用动画效果,能带给用户更好的感觉.做动画可以通过XML或Android代码.本教程中,介绍使用XML来做动画.在这里,介绍基本的动画,如淡入,淡出,旋转等. 效果: htt ...
随机推荐
- target标签对于优化用户体验的作用
最近开始关注target="_blank"标签,是源于对咨询区的采纳工作.帖子内容页是在原页面加载,这样问题就来了,每采纳完一个问题,必须得后退好几次才可以,很不方便.后来按ctr ...
- ES mlockall作用——preventing that memory from being paged to the swap area
elasticsearch还有一个重要的参数bootstrap.mlockall,这个参数的目的是当你无法关闭系统的swap的时候,建议把这个参数设为true.防止在内存不够用的时候,elastics ...
- BZOJ4006 [JLOI2015]管道连接
裸的状压DP 令$f_S$表示包含颜色集合S的最小斯坦纳生成森林的值,于是有: $$f_S=\min\{f_S,f_s+f_{S-s}|s\subset S\}$$ 然后嘛...还是裸的斯坦纳树搞搞. ...
- BZOJ1570 [JSOI2008]Blue Mary的旅行
建分层图,每一层表示一天的情况 从S向第0层的1号点连边,每层的n向T连INF的边 枚举天数,每多一天就多建一层然后跑最大流,如果当前流量大于人数则输出答案 由于路径长度不会超过n,因此tot个人走这 ...
- linux 设置windows共享
在linux下需要设置windows共享. 我们使用SMBA来实现. 1.查看是否安装smba. rpm -qa | grep samba 如果没有安装,则去 www.rpmfind.net 下载sm ...
- FZU 2092 收集水晶 bfs+记忆化搜索 or 暴力
题目链接:收集水晶 一眼看过去,觉得是普通的bfs,初始位置有两个.仔细想了想...好像如果这样的话..........[不知道怎么说...T_T] dp[12][12][12][12][210] 中 ...
- K最近邻
k算法实现的步骤: 第一:确定K值(就是指最近邻居的个数).一般是一个奇数,因为测试样本个数有限, 第二:确定度量的长度,也就是余弦值,根据公式来算: 然后根据这个距离,排序大小,从中选出前k ...
- IoTimerInLineHook
#ifndef CXX_IOTIMERINLINEHOOK_H # include "IoTimerInlineHook.h" #endif ULONG32 SSDT_NtOpen ...
- windows-docker开发我常用命令 docker-machine ssh default
docker-machine ssh default docker logs test sudo systemctl start docker docker tag IMAGEID ne ...
- POJ 2992 求组合数的因子个数
求C(n,k)的因子个数 C(n,k) = (n*(n-1)*...*(n-k+1))/(1*2*...*k) = p1^k1 * p2^k2 * ... * pt^kt 这里只要计算出分子中素数因子 ...