Android开发——为EditText添加烟花效果的实现
0. 前言
在Android开发中,很多酷炫的效果是增加用户粘性的必要条件。本篇介绍一个为EditText添加烟花效果的示例,效果展示如下。
1. 烟花效果需要关注的点
(1)爆炸的位置:光标所在位置。
(2)火花飞出的方向:这里采用随机方向,0~180度,即只向上。
(3)发射速度:每个火花发射的速度是不一样的,在一定范围内随机。发射后速度衰减。
(4)风速固定:风向根据文字的增长或减少决定。
(5)重力:烟花飞出的应该是一条抛物线。
(6)火花的颜色:单次次发射的所有火花颜色一样,每次发射颜色随机。
(7)什么时候发射烟花:监听EditText的文字改变,获取文字数量的变化以确定风的方向,还有获取光标的位置确定爆炸的位置。光标的位置没有具体的方法确定坐标,要通过反射自己计算。
2. 主要实现类
库里包含三个类:
Element(int color, Double direction, floatspeed)
烟花的小火花,存放颜色,飞行方向,飞行速度这三个变量。
Firework(Location location, int windDirection)
烟花,控制整个烟花的动画,计算小火花的位置并绘制小火花。
FireworkView()
View类,监听EditText中文字的改变,获取光标的位置,并在该位置生成Firework。
3. 一些实现细节
首先我们看看FireworkView的使用方法:
mFireworkView = (FireworkView) findViewById(R.id.fire_work);
mFireworkView.bindEditText(mEditText);
是不是很简单,只要绑定需要呈现烟花效果的EditText就行了。
//Class FireworkView:
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
} @Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
/**
*i为EditText里的字符数,i1为减少的字符数,i2为增加的字符数。
*关于launch的第三个参数,决定风的方向,1为吹向右边,-1为左边。
*/
float [] coordinate = getCursorCoordinate();
launch(coordinate[0], coordinate[1], i1 ==0?-1:1);
} @Override
public void afterTextChanged(Editable editable) {
} private void launch(float x, float y, int direction){
final Firework firework = new Firework(new Firework.Location(x, y), direction);
firework.addAnimationEndListener(new Firework.AnimationEndListener() {
@Override
public void onAnimationEnd() {
//动画结束后把firework移除,当没有firework时不会刷新页面
fireworks.remove(firework);
}
});
fireworks.add(firework);
firework.fire();
invalidate();
}
在bindEditText()中我们监听EditText。当文字有改变时,首先计算文字是增多还是减少,以确定风的方向。然后getCursorCoordinate()获得光标的坐标。最后就可以发射烟花了。
用LinkedList<Firework>保存正在动画的Firework,如果里面Firework的数量不为0就不断地重绘view以实现动画,为0时不重绘。
//Class Firework
public void fire(){
animator = ValueAnimator.ofFloat(1,0);
animator.setDuration(duration);
animator.setInterpolator(new AccelerateInterpolator(2));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
animatorValue = (float) valueAnimator.getAnimatedValue();
//计算每个火花的位置
for (Element element : elements){
element.x = (float) (element.x
+ Math.cos(element.direction)*element.speed*animatorValue
+ windSpeed*windDirection);
element.y = (float) (element.y
- Math.sin(element.direction)*element.speed*animatorValue
+ gravity*(1-animatorValue));
}
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
listener.onAnimationEnd();
}
});
animator.start();
}
用一个ValueAnimator实现动画。由于发射速度是衰减的,所以animator = ValueAnimator.ofFloat(1,0);同时设定一个new AccelerateInterpolator(2),即加速度是增长的。如果对Interpolator不熟悉可以看http://my.oschina.net/banxi/blog/135633 。
Class Firework:
public void draw(Canvas canvas){
mPaint.setAlpha((int) (225*animatorValue));
for (Element element : elements){
canvas.drawCircle(location.x + element.x, location.y + element.y, elementSize, mPaint);
}
}
最后只要不断地绘制小火花就行了。
4. 光标位置的识别
如何获得光标的位置呢?涉及到反射,需要自己查看TextView(EditText的父类是TextView)的源码并理清绘制过程。下面注释说的很清楚了,这里就不再反复说明。
//Class FireworkView
private float[] getCursorCoordinate (){
/*
*以下通过反射获取光标cursor的坐标。
* 首先观察到TextView的invalidateCursorPath()方法,它是光标闪动时重绘的方法。
* 方法的最后有个invalidate(bounds.left + horizontalPadding, bounds.top + verticalPadding,
bounds.right + horizontalPadding, bounds.bottom + verticalPadding);
*即光标重绘的区域,由此可得到光标的坐标
* 具体的坐标在TextView.mEditor.mCursorDrawable里,获得Drawable之后用getBounds()得到Rect。
* 之后还要获得偏移量修正,通过以下三个方法获得:
* getVerticalOffset(),getCompoundPaddingLeft(),getExtendedPaddingTop()。
*
*/ int xOffset = 0;
int yOffset = 0;
Class<?> clazz = EditText.class;
clazz = clazz.getSuperclass();
try {
Field editor = clazz.getDeclaredField("mEditor");
editor.setAccessible(true);
Object mEditor = editor.get(mEditText);
Class<?> editorClazz = Class.forName("android.widget.Editor");
Field drawables = editorClazz.getDeclaredField("mCursorDrawable");
drawables.setAccessible(true);
Drawable[] drawable= (Drawable[]) drawables.get(mEditor); Method getVerticalOffset = clazz.getDeclaredMethod("getVerticalOffset",boolean.class);
Method getCompoundPaddingLeft = clazz.getDeclaredMethod("getCompoundPaddingLeft");
Method getExtendedPaddingTop = clazz.getDeclaredMethod("getExtendedPaddingTop");
getVerticalOffset.setAccessible(true);
getCompoundPaddingLeft.setAccessible(true);
getExtendedPaddingTop.setAccessible(true);
if (drawable != null ){
if (drawable[0] != null){
Rect bounds = drawable[0].getBounds();
Log.d(TAG,bounds.toString());
xOffset = (int) getCompoundPaddingLeft.invoke(mEditText) + bounds.left;
yOffset = (int) getExtendedPaddingTop.invoke(mEditText) + (int)getVerticalOffset.invoke(mEditText, false)+bounds.bottom;
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
float x = mEditText.getX() + xOffset;
float y = mEditText.getY() + yOffset; return new float[]{ x , y};
}
Github地址:https://github.com/covetcode/EditTextFirework-Demo
原文地址:http://www.jianshu.com/p/a001192aaa4b
Android开发——为EditText添加烟花效果的实现的更多相关文章
- Android开发之动态添加控件
动态添加TextView控件: 一:创建一个Android project项目 activity_main.xml文件: 1.用两个LinearLayout布局分别包裹一对TextView,EditT ...
- Android开发学习之路-3DTouch效果模仿
3D Touch是什么效果的大家应该都知道了.什么?不知道,那也没办法呀,我也没有iPhone 6s演示给你看的. 本篇博客要做的效果图: 来个低质量动图: 这个动图效果不是很好,实际上模糊效果应该是 ...
- Android 开发笔记___textview_聊天室效果
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- android开发学习 ------- 仿QQ侧滑效果的实现
需要做一个仿QQ侧滑删除的一个效果: 一开始是毫无头绪,百度找思路,找到 https://blog.csdn.net/xiaxiazaizai01/article/details/53036994 ...
- 【Android开发】安卓炫酷效果集合
1. android-ripple-background 能产生波浪效果的背景图片控件,可以自定义颜色,波浪扩展的速度,波浪的圈数. github地址 2. android-shapeLoadingV ...
- android 开发 - 对图片进行虚化(毛玻璃效果,模糊)
概述 IPAD,IPHONE上首页背景的模糊效果是不是很好看,那么在 Android中如何实现呢.我通过一种方式实现了这样的效果. 开源库名称:anroid-image-blur 一个android ...
- Android开发中EditText的点击Enter键焦点改变处理(获取焦点和失去焦点交互变化)
最近因为项目需要,需要将EditText的焦点转移到LineraLayout上: 即为EditText输入完毕后,点击回车键或者按压其他嵌入式android设备的OK键,获取LineraLayout的 ...
- Android 开发笔记___textvieww__跑马灯效果
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- Android开发:在EditText中关闭软键盘 转来的
1.EditText有焦点(focusable为true)阻止输入法弹出 editText=(EditText)findViewById(R.id.txtBody); editText.setOnTo ...
随机推荐
- SQL2008R2数据库日志太大收缩方法
1.登陆项目平台数据库服务器.双击SQL Server Management Studio打开数据库管理.登陆数据库 2.如下图,打开数据库属性窗口 3.如下图,更改数据库恢复模式 4.如下图,收缩数 ...
- 基于localStorge开发登录模块的记住密码与自动登录
前沿||我是乐于分享,善于交流的鸟窝 先做写一篇关于登录模块中记住密码与自动登录的模块.鸟窝微信:jkxx123321 关于这个模块功能模块的由来,这是鸟大大的处女秀,为什么这么说呢?一天在群里,一个 ...
- [Android] Spinners介绍及用法
本文地址:http://www.cnblogs.com/rossoneri/p/4366018.html Spinners介绍 Spinners提供了从一个集(set)中选择某个值(value)的一个 ...
- linux 查找匹配文件中包含指定字符的 前五行,这里是指所有匹配的前五行
最近被问到 一个关于查找匹配字符的信息显示问题: 系统/etc/sysctl.conf文件会定义系统内核的一些配置,请查找和net有关的信息,并只打印前面5行信息. 解决方式大概试两种写法均可: 1. ...
- AWS服务学习
什么是云计算? 云计算是用户通过Internet云服务平台按需提供计算能力.数据库存储.应用程序和其他IT资源,采用按需支付定价模式 无论您是在运行拥有数百万移动用户的照片共享应用程序,还是要为您的业 ...
- 第二次项目冲刺(Beta版本)2017/12/10
一.任务分布 二.燃尽图 三.站立式会议 1.照片(再给我两分钟) 2.任务安排 四.总结 冲刺的最后一天了,时间安排的不够好,还有部分功能没有完成,大家都尽力了,我们后续会抓紧时间完成项目.
- Ecstore 默认图片压缩质量差的问题解决方法
修改app/image/lib/clip.php文件 }elseif( function_exists('imagecopyresampled')){ $quality = 80; $image_p ...
- python spawnv用法
test.py import os import string def run(program, *args): file = program result = os.spawnv(os.P_WAIT ...
- es6安装babel包
1.前面下载node.js及安装淘宝镜像可以查看我写的vue.js环境搭建 2.安装完node后,安装babel npm install -g babel-cli 3.检验babel是否安装成功: b ...
- JS控制div跳转到指定的位置的几种解决方案总结
原文:http://www.jb51.net/article/96574.htm 这篇文章主要介绍了JS控制div跳转到指定的位置的几种解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考 ...