Android中画布连线的连线动画的实现
一.实现在画布中连线的动画的效果,如图所示:
二.功能实现的初始想法:
1.要实现划线的动画的效果,在我所写得画布中有这样两个方法用于连线的拖动,思路就是从这里来的,通过沿直线方向的拖动就可以实现如图的划线动画的效果:
/** * 设置控件前一连线的移动 * * @param drawableMap * @param x * @param y * @param nextWidgetIndex */ public static void setProLineMove(HashMap<Integer, CDrawable> drawableMap, int x, int y, int nextWidgetIndex) {CDrawable cd = drawableMap.get(nextWidgetIndex); if (null != cd) {int xcoords = cd.getXcoords(); int ycoords = cd.getYcoords(); if (CanvsUtils.isActionWidgetTypeInstance(cd)) {int lineIndex = ((ActionWidget) cd).getNextLineIndex(); //获取保存在控件中的连线值 CanvasViewLigatureUtils.setLineFollowMove(drawableMap, x, y, xcoords, ycoords, lineIndex); }} }/** * 设置控件后一连线的移动 * * @param drawableMap * @param x * @param y * @param nextWidgetIndex */ public static void setNextLineMove(HashMap<Integer, CDrawable> drawableMap, int x, int y, int nextWidgetIndex) {CDrawable cd = drawableMap.get(nextWidgetIndex); if (null != cd) {int xcoords = cd.getXcoords(); int ycoords = cd.getYcoords(); if (CanvsUtils.isActionWidgetTypeInstance(cd)) {int lineIndex = ((ActionWidget) cd).getProLineIndex(); //获取保存在控件中的连线值 setLineFollowMove(drawableMap, xcoords, ycoords, x, y, lineIndex); }} }
/** * 设置坐标使得连线跟随着滑动变化 * * @param x * @param y * @param xcoords * @param ycoords * @param lineIndex */ public static void setLineFollowMove(HashMap<Integer, CDrawable> drawableMap, int x, int y, int xcoords, int ycoords, int lineIndex) {if (lineIndex < 0) {return; }CPath drawable = (CPath) drawableMap.get(lineIndex); if (drawable!=null){drawable.setXcoords(xcoords); drawable.setYcoords(ycoords); drawable.setEndX(x); drawable.setEndY(y); } }
2.首要解决的就是获取到线段上点的集合:
/** * 从直线中获取点 * * @param startX * @param startY * @param endX * @param endY * @param span 获取点的跨度值,可用于连线动画的速度计算 * @return */ public static List<PointModle> getPointFromLine(int startX, int startY, int endX, int endY, int span) {List<PointModle> list = new ArrayList<>(); if (startX == endX) {int from = Math.min(startY, endY); int to = Math.max(startX, endY); for (int y = from; y <= to; y++) {list.add(new PointModle(startX, y)); }} else {double slope = ((double) (endY - startY)) / ((double) (endX - startX)); int step = (endX > startX) ? span : -span; double y = 0; if (step>0){for (int x = startX; x < endX; x += step) {y = ((x - startX) * slope + startY); list.add(new PointModle(x, y)); }}else {for (int x = startX; x > endX; x += step) {y = ((x - startX) * slope + startY); list.add(new PointModle(x, y)); }}}return list; }
3.接下来就是用定时器来控制划线的速度(即是设置沿着直线方向的所要设置的X、Y的坐标):
/** * 实现直线随着直线方向进行移动 * * @param pointFromLine * @param key * @param startX * @param startY */ private void setLineAnim(List<PointModle> pointFromLine, int key, int startX, int startY, int endX, int endY) {if (pointFromLine.size() < 0) {return; }if ((pointAmount < pointFromLine.size()) && (pointFromLine.size() > 0)) {Log.i("everb","划线中"); CanvasViewLigatureUtils.setLineFollowMove(drawableMap, startX, startY, (int) pointFromLine.get(pointAmount).getX(), (int) pointFromLine.get(pointAmount).getY(), key); } else {CanvasViewLigatureUtils.setLineFollowMove(drawableMap, startX, startY, endX, endY, key); mLink++; ((ActionWidget) drawableMap.get(mActionFrame2Linked.get(mActionFrame))).setPaint(redPaint); mActionFrame++; mHandler.sendEmptyMessageAtTime(NEXT_LINK_ANIM, 0); } }
4.这里在画一条线段时用定时器去设置,等一条线的动画完成之后。用Handler去通知下一条线段动画的开始。这样周而复始就可以实现如上GIT图的连线动画的效果:
mHandler = new Handler() {@Override public void handleMessage(Message msg) {super.handleMessage(msg); // Log.i("everb", "handler的值:" + msg.what); switch (msg.what) {case NEXT_LINK_ANIM: {pointAmount = 0; if (mLink < mSegment2Linked.size()) {motorPreviewDrawProgress(50, Color.BLACK, 20f); } else {//划线动画结束的操作 setActionFrameAlpha(false); motorPreviewDrawProgressLineClean(); mTimer.cancel(); }}break; }}};
三.这个功能是基于我之前写的有关画布的基础上实现,下面贴出连线动画的帮助类的代码:
package com.example.administrator.canvasdemo.helper; import android.content.Context; import android.graphics.Color; import android.graphics.Paint; import android.os.Handler; import android.os.Message; import android.util.Log; import com.example.administrator.canvasdemo.MainActivity; import com.example.administrator.canvasdemo.modle.PointModle; import com.example.administrator.canvasdemo.utils.CanvasViewLigatureUtils; import com.example.administrator.canvasdemo.view.ActionCanvasView; import com.example.administrator.canvasdemo.view.ActionWidget; import com.example.administrator.canvasdemo.view.CDrawable; import com.example.administrator.canvasdemo.view.CPath; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; /** * @author wangyao * @package com.example.administrator.canvasdemo.helper * @date 2017/12/9 18:50 * @describe TODO * @project */ public class LineToAnimHelper {private List<Integer> mPreviewLineList; private TimerTask mTimerTask; private Timer mTimer; private Context mContext; private int mScreenWidth; private int pointAmount; //线段上点的数量 private HashMap<Integer, CDrawable> drawableMap; private ActionCanvasView mActionCanvasView; private int mKey; //标记index的变化 private List<Integer> mActionFrame2Linked; private List<CPath> mSegment2Linked; private int mLink; //当前正在划线的index private int mActionFrame = 1; //连线的关键帧集合中的index private Handler mHandler; private List<PointModle> mPointFromLine; //获取线段的点的集合 private static final int NEXT_LINK_ANIM = -1; private boolean isActionFrameAnimStop = false; private Paint redPaint; private Paint bluePaint; public LineToAnimHelper(Context context, HashMap<Integer, CDrawable> drawableMap, ActionCanvasView actionCanvasView, int key) {mTimer = new Timer(); mPreviewLineList = new ArrayList<>(); this.mContext = context; this.drawableMap = drawableMap; this.mActionCanvasView = actionCanvasView; this.mKey = key; mPointFromLine = new ArrayList<>(); redPaint=new Paint(); bluePaint=new Paint(); }/** * 执行的划线动画 */ public void executeLineToAnim() {redPaint.setColor(Color.RED); bluePaint.setColor(Color.BLUE); mHandler = new Handler() {@Override public void handleMessage(Message msg) {super.handleMessage(msg); // Log.i("everb", "handler的值:" + msg.what); switch (msg.what) {case NEXT_LINK_ANIM: {pointAmount = 0; if (mLink < mSegment2Linked.size()) {motorPreviewDrawProgress(50, Color.BLACK, 20f); } else {//划线动画结束的操作 setActionFrameAlpha(false); motorPreviewDrawProgressLineClean(); mTimer.cancel(); }}break; }}}; if (drawableMap.size() < 0 ) {return; }mActionFrame2Linked = getActionFrame2Linked(); mSegment2Linked = getSegment2Linked(); setActionFrameAlpha(true); motorPreviewDrawProgress(50, Color.BLACK, 20f); mTimer.schedule(mTimerTask, 0, 100); }/** * 退出预览的划线动画 */ public void motorPreviewQuit() {mTimer.cancel(); setActionFrameAlpha(false); recoveryActionFrameBitmap(); motorPreviewDrawProgressLineClean(); }/** * 获取连上线的线段 * * @return */ private List<CPath> getSegment2Linked() {List<CPath> segment2LinkedList = new ArrayList<>(); int searchIndex = 0; ActionWidget fristActionFrame = (ActionWidget) drawableMap.get(0); if (fristActionFrame.getNextLineIndex() < 0) {return null; }segment2LinkedList.add((CPath) drawableMap.get(fristActionFrame.getNextLineIndex())); searchIndex = fristActionFrame.getNextWidget(); while (searchIndex > 0) {int nextLineIndex = ((ActionWidget) drawableMap.get(searchIndex)).getNextLineIndex(); if (nextLineIndex > 0) {segment2LinkedList.add((CPath) drawableMap.get(nextLineIndex)); }searchIndex = ((ActionWidget) drawableMap.get(searchIndex)).getNextWidget(); }return segment2LinkedList; }/** * 设置未连接上关键帧的透明度 * * @param isSetAlpha */ private void setActionFrameAlpha(boolean isSetAlpha) {for (Map.Entry<Integer, CDrawable> entry : drawableMap.entrySet()) {if (entry.getValue() instanceof ActionWidget) {ActionWidget widget = (ActionWidget) entry.getValue(); if ((widget.getNextLineIndex() < 0) && (widget.getProLineIndex() < 0)) {if (isSetAlpha) {setActionFrameAlpha(widget); } else {recoveryActionFrameAlpha(widget); }}}}}/** * 获取连上线控件的Index值及顺序 * * @return */ private List<Integer> getActionFrame2Linked() {List<Integer> actionFrame2LinedList = new ArrayList<>(); int searchIndex = 0; ActionWidget fristActionFrame = (ActionWidget) drawableMap.get(0); if (fristActionFrame.getNextLineIndex() < 0) {return null; }actionFrame2LinedList.add(searchIndex); searchIndex = fristActionFrame.getNextWidget(); while (searchIndex > 0) {actionFrame2LinedList.add(searchIndex); searchIndex = ((ActionWidget) drawableMap.get(searchIndex)).getNextWidget(); }return actionFrame2LinedList; }/** * 清除预览模式的划线 */ private void motorPreviewDrawProgressLineClean() {for (int i = 0; i < mPreviewLineList.size(); i++) {drawableMap.remove(mPreviewLineList.get(i)); }mActionCanvasView.invalidate(); }/** * 传入两点的坐标在画布中进行划线动画 * * @param time 两帧运行时间 * @param color * @param width */ private void motorPreviewDrawProgress(int time, int color, float width) {mPointFromLine.clear(); // 定时器的间隔时间可以计算出传入的点的跨度值从而控制动画的速度 mPointFromLine = CanvasViewLigatureUtils.getPointFromLine(mSegment2Linked.get(mLink).getXcoords(), mSegment2Linked.get(mLink).getYcoords(), mSegment2Linked.get(mLink).getEndX(), mSegment2Linked.get(mLink).getEndY(), 5); mKey++; mPreviewLineList.add(mKey); CanvasViewLigatureUtils.setLineTo(mActionCanvasView, mKey, 0, 0, 0, 0, color, width); mTimerTask = new TimerTask() {@Override public void run() {setLineAnim(mPointFromLine, mKey, mSegment2Linked.get(mLink).getXcoords(), mSegment2Linked.get(mLink).getYcoords(), mSegment2Linked.get(mLink).getEndX(), mSegment2Linked.get(mLink).getEndY()); if (!isActionFrameAnimStop) {pointAmount++; }mActionCanvasView.post(new Runnable() {@Override public void run() {mActionCanvasView.invalidate(); }}); }}; }/** * 实现直线随着直线方向进行移动 * * @param pointFromLine * @param key * @param startX * @param startY */ private void setLineAnim(List<PointModle> pointFromLine, int key, int startX, int startY, int endX, int endY) {if (pointFromLine.size() < 0) {return; }if ((pointAmount < pointFromLine.size()) && (pointFromLine.size() > 0)) {Log.i("everb","划线中"); CanvasViewLigatureUtils.setLineFollowMove(drawableMap, startX, startY, (int) pointFromLine.get(pointAmount).getX(), (int) pointFromLine.get(pointAmount).getY(), key); } else {CanvasViewLigatureUtils.setLineFollowMove(drawableMap, startX, startY, endX, endY, key); mLink++; ((ActionWidget) drawableMap.get(mActionFrame2Linked.get(mActionFrame))).setPaint(redPaint); mActionFrame++; mHandler.sendEmptyMessageAtTime(NEXT_LINK_ANIM, 0); }}/** * 获取两点的距离 * * @param pointModle1 * @param pointModle2 * @return */ private double getDistance(PointModle pointModle1, PointModle pointModle2) {double x = Math.abs(pointModle1.getX() - pointModle2.getY()); double y = Math.abs(pointModle1.getY() - pointModle2.getY()); return Math.sqrt(x * x + y * y); }/** * 设置控件透明度 * * @param keyFrameWidget */ private void setActionFrameAlpha(ActionWidget keyFrameWidget) {Paint paint = new Paint(); paint.setAlpha(90); keyFrameWidget.setPaint(paint); }/** * 恢复控件透明度 * * @param keyFrameWidget */ private void recoveryActionFrameAlpha(ActionWidget keyFrameWidget) {Paint paint = new Paint(); paint.setAlpha(255); keyFrameWidget.setPaint(paint); }/** * 恢复划线动画之前的图片原样 */ private void recoveryActionFrameBitmap() {((ActionWidget) drawableMap.get(0)).setPaint(bluePaint); for (int i = 1; i < mActionFrame2Linked.size(); i++) {((ActionWidget) drawableMap.get(mActionFrame2Linked.get(i))).setPaint(bluePaint); }}/** * 控制划线动画的停止与继续 * * @param isAnimStop */ public void motorPreViewCtrl(boolean isAnimStop) {isActionFrameAnimStop = isAnimStop; if (isActionFrameAnimStop) {// 划线动画暂停 }} }
四、Demo下载的地址
Android中画布连线的连线动画的实现相关推荐
- android开发上下翻转动画,怎么在android中利用FlipAnimation实现一个3D垂直翻转动画...
怎么在android中利用FlipAnimation实现一个3D垂直翻转动画 发布时间:2021-02-20 17:08:30 来源:亿速云 阅读:122 作者:Leah 这期内容当中小编将会给大家带 ...
- Android中实现一个简单的逐帧动画(附代码下载)
场景 Android中的逐帧动画,就是由连续的一张张照片组成的动画. 效果 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 ...
- android 张口逐帧动画,Android中实现一个简单的逐帧动画(附代码下载)
场景 Android中的逐帧动画,就是由连续的一张张照片组成的动画. 效果 注: 实现 首先准备一组不同表情的照片,放在res/drawable下,然后在此目录下新建动画资源文件fairy.xml 这 ...
- android中画布大小设置,如何设置canvas大小?
我试图实现一个简单的应用程序,在主要活动中绘制一个黑色矩形,按下按钮. 例如,在MainActivity : private Button button1; public void onCreate( ...
- Android中使用SurfaceView和Canvas来绘制动画
事实上每一个View中都有Canvas能够用来绘制动画.仅仅须要在这个View中重载onDraw()方法就能够,可是SurfaceView类是一个专门用来制动动画的类. Canvas(中文叫做&quo ...
- Android 中通过Canvas 与线程结合实现动画效果
前段时间在公司做了一个模块,不使用第三方动画效果类,直接通过Canvas 进行图像的绘制,并通过Thread实现动画的效果 该模块主要是实现车辆运行时候的道路运行效果,在进行实施前做了一个相关的Dem ...
- 六、Android中的Animation与炫酷开场动画
本文目录 一.属性动画和MaterialDesign动画 属性动画和MaterialDesign动画相关的内容,已经在前面写过,具体查看https://www.jianshu.com/p/15d256 ...
- Android中的动画
视频课:https://edu.csdn.net/course/play/7621 学习内容 Ø 帧动画 Ø 补间动画 Ø 动画方式切换组件 能力目标 Ø 掌握Android中动画的基本概念及分类 Ø ...
- android贝塞尔曲线实例,android中贝塞尔曲线的应用示例
前言: 贝塞尔曲线又称贝兹曲线,它的主要意义在于无论是直线或曲线都能在数学上予以描述.最初由保罗·德卡斯特里奥(Paul de Casteljau)于1959年运用德卡斯特里奥演算法开发(de Cas ...
最新文章
- 我国科学家成功研制全球神经元规模最大的类脑计算机
- Python项目可以有多大?最多可以有多少行代码?
- 一个风骚的C语言操作
- 计算机专业跨专业考文科,给07年想跨专业考湖大计算机专业的同学
- Java中httpClient中的设置超时时间
- PXC 安装 for 5.7
- git 中遇到的错误及解决方法
- 免费的中文OCR软件
- python读取cad_SmartSoft中用C#.Net实现AutoCAD块属性提取|python基础教程|python入门|python教程...
- [转]魔兽世界私服Trinity,从源码开始
- oracle数据库左链接,Oracle数据库中的左连接与右连接
- CAE软件技术现状调研
- 统计字符串中数字字符、英文字符、空格符的个数
- TEANMA(天玛)-公共广播系统中扬声器配置及相关注意事项解析
- 项目管理提升绩效考核的方法
- 【Cucumber】【问题集锦】
- 编写一个简单的NodeBB插件
- 43款设计师必备英文设计字体【书法类字体】
- 爬取拉钩网60条招聘信息并存入数据库
- 磁场检测传感器的设计