版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】android如何实现直播点赞飘心动画效果
这篇文章给大家分享的是有关android如何实现直播点赞飘心动画效果的内容。在下觉得挺实用的,因此分享给大家做个参考,一起跟随在下过来看看吧。前段时间在写直播的时候,需要观众在看直播的时候点赞的效果,在此参照了腾讯大神写的点赞(飘心动画效果)。下面是效果图:1.自定义飘心动画的属性在attrs.xml中增加自定义的属性<!--
飘心动画自定义的属性
-->
<declare-styleable
name="HeartLayout">
<attr
name="initX"
format="dimension"/>
<attr
name="initY"
format="dimension"/>
<attr
name="xRand"
format="dimension"/>
<attr
name="animLengthRand"
format="dimension"/>
<attr
name="xPointFactor"
format="dimension"/>
<attr
name="animLength"
format="dimension"/>
<attr
name="heart_width"
format="dimension"/>
<attr
name="heart_height"
format="dimension"/>
<attr
name="bezierFactor"
format="integer"/>
<attr
name="anim_duration"
format="integer"/>
</declare-styleable>2.定义飘心默认值2.1dimens.xml<!--
飘星
-->
<dimen
name="heart_anim_bezier_x_rand">50.0dp</dimen>
<dimen
name="heart_anim_init_x">50.0dp</dimen>
<dimen
name="heart_anim_init_y">25.0dp</dimen>
<dimen
name="heart_anim_length">400.0dp</dimen>
<dimen
name="heart_anim_length_rand">350.0dp</dimen>
<dimen
name="heart_anim_x_point_factor">30.0dp</dimen>
<dimen
name="heart_size_height">27.3dp</dimen>
<dimen
name="heart_size_width">32.5dp</dimen>2.2integers.xml<?xml
version="1.0"
encoding="utf-8"?>
<resources>
<integer
name="heart_anim_bezier_factor">6</integer>
<integer
name="anim_duration">3000</integer>
</resources>3.定义飘心动画控制器3.1AbstractPathAnimator.javapublic
abstract
class
AbstractPathAnimator
{
private
final
Random
mRandom;
protected
final
Config
mConfig;
public
AbstractPathAnimator(Config
config)
{
mConfig
=
config;
mRandom
=
new
Random();
}
public
float
randomRotation()
{
return
mRandom.nextFloat()
*
28.6F
-
14.3F;
}
public
Path
createPath(AtomicInteger
counter,
View
view,
int
factor)
{
Random
r
=
mRandom;
int
x
=
r.nextInt(mConfig.xRand);
int
x2
=
r.nextInt(mConfig.xRand);
int
y
=
view.getHeight()
-
mConfig.initY;
int
y2
=
Value()
*
15
+
mConfig.animLength
*
factor
+
r.nextInt(mConfig.animLengthRand);
factor
=
y2
/
mConfig.bezierFactor;
x
=
mConfig.xPointFactor
+
x;
x2
=
mConfig.xPointFactor
+
x2;
int
y3
=
y
-
y2;
y2
=
y
-
y2
/
2;
Path
p
=
new
Path();
p.moveTo(mConfig.initX,
y);
p.cubicTo(mConfig.initX,
y
-
factor,
x,
y2
+
factor,
x,
y2);
p.moveTo(x,
y2);
p.cubicTo(x,
y2
-
factor,
x2,
y3
+
factor,
x2,
y3);
return
p;
}
public
abstract
void
start(View
child,
ViewGroup
parent);
public
static
class
Config
{
public
int
initX;
public
int
initY;
public
int
xRand;
public
int
animLengthRand;
public
int
bezierFactor;
public
int
xPointFactor;
public
int
animLength;
public
int
heartWidth;
public
int
heartHeight;
public
int
animDuration;
static
public
Config
fromTypeArray(TypedArray
typedArray,
float
x,
float
y,
int
pointx,
int
heartWidth,
int
heartHeight)
{
Config
config
=
new
Config();
Resources
res
=
typedArray.getResources();
config.initX
=
(int)
typedArray.getDimension(R.styleable.HeartLayout_initX,
x);
config.initY
=
(int)
typedArray.getDimension(R.styleable.HeartLayout_initY,
y);
config.xRand
=
(int)
typedArray.getDimension(R.styleable.HeartLayout_xRand,
res.getDimensionPixelOffset(R.dimen.heart_anim_bezier_x_rand));
config.animLength
=
(int)
typedArray.getDimension(R.styleable.HeartLayout_animLength,
res.getDimensionPixelOffset(R.dimen.heart_anim_length));//动画长度
config.animLengthRand
=
(int)
typedArray.getDimension(R.styleable.HeartLayout_animLengthRand,
res.getDimensionPixelOffset(R.dimen.heart_anim_length_rand));
config.bezierFactor
=
typedArray.getInteger(R.styleable.HeartLayout_bezierFactor,
res.getInteger(R.integer.heart_anim_bezier_factor));
config.xPointFactor
=
pointx;
//
config.heartWidth
=
(int)
typedArray.getDimension(R.styleable.HeartLayout_heart_width,
//
res.getDimensionPixelOffset(R.dimen.heart_size_width));//动画图片宽度
//
config.heartHeight
=
(int)
typedArray.getDimension(R.styleable.HeartLayout_heart_height,
//
res.getDimensionPixelOffset(R.dimen.heart_size_height));//动画图片高度
config.heartWidth
=
heartWidth;
config.heartHeight
=
heartHeight;
config.animDuration
=
typedArray.getInteger(R.styleable.HeartLayout_anim_duration,
res.getInteger(R.integer.anim_duration));//持续期
return
config;
}
}
}3.2PathAnimator.java/**
*
飘心路径动画器
*/
public
class
PathAnimator
extends
AbstractPathAnimator
{
private
final
AtomicInteger
mCounter
=
new
AtomicInteger(0);
private
Handler
mHandler;
public
PathAnimator(Config
config)
{
super(config);
mHandler
=
new
Handler(Looper.getMainLooper());
}
@Override
public
void
start(final
View
child,
final
ViewGroup
parent)
{
parent.addView(child,
new
ViewGroup.LayoutParams(mConfig.heartWidth,
mConfig.heartHeight));
FloatAnimation
anim
=
new
FloatAnimation(createPath(mCounter,
parent,
2),
randomRotation(),
parent,
child);
anim.setDuration(mConfig.animDuration);
anim.setInterpolator(new
LinearInterpolator());
anim.setAnimationListener(new
Animation.AnimationListener()
{
@Override
public
void
onAnimationEnd(Animation
animation)
{
mHandler.post(new
Runnable()
{
@Override
public
void
run()
{
parent.removeView(child);
}
});
mCounter.decrementAndGet();
}
@Override
public
void
onAnimationRepeat(Animation
animation)
{
}
@Override
public
void
onAnimationStart(Animation
animation)
{
mCounter.incrementAndGet();
}
});
anim.setInterpolator(new
LinearInterpolator());
child.startAnimation(anim);
}
static
class
FloatAnimation
extends
Animation
{
private
PathMeasure
mPm;
private
View
mView;
private
float
mDistance;
private
float
mRotation;
public
FloatAnimation(Path
path,
float
rotation,
View
parent,
View
child)
{
mPm
=
new
PathMeasure(path,
false);
mDistance
=
mPm.getLength();
mView
=
child;
mRotation
=
rotation;
parent.setLayerType(View.LAYER_TYPE_HARDWARE,
null);
}
@Override
protected
void
applyTransformation(float
factor,
Transformation
transformation)
{
Matrix
matrix
=
transformation.getMatrix();
mPm.getMatrix(mDistance
*
factor,
matrix,
PathMeasure.POSITION_MATRIX_FLAG);
mView.setRotation(mRotation
*
factor);
float
scale
=
1F;
if
(3000.0F
*
factor
<
200.0F)
{
scale
=
scale(factor,
0.0D,
0.06666667014360428D,
0.20000000298023224D,
1.100000023841858D);
}
else
if
(3000.0F
*
factor
<
300.0F)
{
scale
=
scale(factor,
0.06666667014360428D,
0.10000000149011612D,
1.100000023841858D,
1.0D);
}
mView.setScaleX(scale);
mView.setScaleY(scale);
transformation.setAlpha(1.0F
-
factor);
}
}
private
static
float
scale(double
a,
double
b,
double
c,
double
d,
double
e)
{
return
(float)
((a
-
b)
/
(c
-
b)
*
(e
-
d)
+
d);
}
}4.定义飘心界面4.1HeartView.java/**
*
飘心动画的界面
*/
public
class
HeartView
extends
ImageView{
//绘制的时候抗锯齿
private
static
final
Paint
sPaint
=
new
Paint(Paint.ANTI_ALIAS_FLAG
|
Paint.FILTER_BITMAP_FLAG);
private
static
final
Canvas
sCanvas
=
new
Canvas();
private
int
mHeartResId
=
R.drawable.heart0;
private
int
mHeartBorderResId
=
R.drawable.heart1;
private
static
Bitmap
sHeart;
private
static
Bitmap
sHeartBorder;
public
HeartView(Context
context)
{
super(context);
}
public
HeartView(Context
context,
AttributeSet
attrs)
{
super(context,
attrs);
}
public
HeartView(Context
context,
AttributeSet
attrs,
int
defStyleAttr)
{
super(context,
attrs,
defStyleAttr);
}
public
void
setDrawable(int
resourceId){
Bitmap
heart
=
BitmapFactory.decodeResource(getResources(),
resourceId);
//
Sets
a
drawable
as
the
content
of
this
ImageView.
setImageDrawable(new
BitmapDrawable(getResources(),heart));
}
public
void
setColor(int
color)
{
Bitmap
heart
=
createHeart(color);
setImageDrawable(new
BitmapDrawable(getResources(),
heart));
}
public
void
setColorAndDrawables(int
color,
int
heartResId,
int
heartBorderResId)
{
if
(heartResId
!=
mHeartResId)
{
sHeart
=
null;
}
if
(heartBorderResId
!=
mHeartBorderResId)
{
sHeartBorder
=
null;
}
mHeartResId
=
heartResId;
mHeartBorderResId
=
heartBorderResId;
setColor(color);
}
public
Bitmap
createHeart(int
color)
{
if
(sHeart
==
null)
{
sHeart
=
BitmapFactory.decodeResource(getResources(),
mHeartResId);
}
if
(sHeartBorder
==
null)
{
sHeartBorder
=
BitmapFactory.decodeResource(getResources(),
mHeartBorderResId);
}
Bitmap
heart
=
sHeart;
Bitmap
heartBorder
=
sHeartBorder;
Bitmap
bm
=
createBitmapSafely(heartBorder.getWidth(),
heartBorder.getHeight());
if
(bm
==
null)
{
return
null;
}
Canvas
canvas
=
sCanvas;
canvas.setBitmap(bm);
Paint
p
=
sPaint;
canvas.drawBitmap(heartBorder,
0,
0,
p);
p.setColorFilter(new
PorterDuffColorFilter(color,
PorterDuff.Mode.SRC_ATOP));
float
dx
=
(heartBorder.getWidth()
-
heart.getWidth())
/
2f;
float
dy
=
(heartBorder.getHeight()
-
heart.getHeight())
/
2f;
canvas.drawBitmap(heart,
dx,
dy,
p);
p.setColorFilter(null);
canvas.setBitmap(null);
return
bm;
}
private
static
Bitmap
createBitmapSafely(int
width,
int
height)
{
try
{
return
Bitmap.createBitmap(width,
height,
Bitmap.Config.ARGB_8888);
}
catch
(OutOfMemoryError
error)
{
error.printStackTrace();
}
return
null;
}
}4.2飘心动画路径布局HeartLayout.java/**
*
飘心动画路径
*/
public
class
HeartLayout
extends
RelativeLayout
implements
View.OnClickListener
{
private
AbstractPathAnimator
mAnimator;
private
AttributeSet
attrs
=
null;
private
int
defStyleAttr
=
0;
private
OnHearLayoutListener
onHearLayoutListener;
private
static
HeartHandler
heartHandler;
private
static
HeartThread
heartThread;
public
void
setOnHearLayoutListener(OnHearLayoutListener
onHearLayoutListener)
{
this.onHearLayoutListener
=
onHearLayoutListener;
}
public
interface
OnHearLayoutListener
{
boolean
onAddFavor();
}
public
HeartLayout(Context
context)
{
super(context);
findViewById(context);
}
public
HeartLayout(Context
context,
AttributeSet
attrs)
{
super(context,
attrs);
this.attrs
=
attrs;
findViewById(context);
}
public
HeartLayout(Context
context,
AttributeSet
attrs,
int
defStyleAttr)
{
super(context,
attrs,
defStyleAttr);
this.attrs
=
attrs;
this.defStyleAttr
=
defStyleAttr;
findViewById(context);
}
private
Bitmap
bitmap;
private
void
findViewById(Context
context)
{
LayoutInflater.from(context).inflate(R.layout.ly_periscope,
this);
bitmap
=
BitmapFactory.decodeResource(getResources(),
R.drawable.icon_like);
dHeight
=
bitmap.getWidth()/2;
dWidth
=
bitmap.getHeight()/2;
textHight
=
sp2px(getContext(),
20)
+
dHeight
/
2;
pointx
=
dWidth;//随机上浮方向的x坐标
bitmap.recycle();
}
private
int
mHeight;
private
int
mWidth;
private
int
textHight;
private
int
dHeight;
private
int
dWidth;
private
int
initX;
private
int
pointx;
public
static
int
sp2px(Context
context,
float
spValue)
{
final
float
fontScale
=
context.getResources().getDisplayMetrics().scaledDensity;
return
(int)
(spValue
*
fontScale
+
0.5f);
}
public
class
HeartHandler
extends
Handler
{
public
final
static
int
MSG_SHOW
=
1;
WeakReference<HeartLayout>
wf;
public
HeartHandler(HeartLayout
layout)
{
wf
=
new
WeakReference<HeartLayout>(layout);
}
@Override
public
void
handleMessage(Message
msg)
{
super.handleMessage(msg);
HeartLayout
layout
=
wf.get();
if
(layout
==
null)
return;
switch
(msg.what)
{
case
MSG_SHOW:
addFavor();
break;
}
}
}
public
class
HeartThread
implements
Runnable
{
private
long
time
=
0;
private
int
allSize
=
0;
public
void
addTask(long
time,
int
size)
{
this.time
=
time;
allSize
+=
size;
}
public
void
clean()
{
allSize
=
0;
}
@Override
public
void
run()
{
if
(heartHandler
==
null)
return;
if
(allSize
>
0)
{
heartHandler.sendEmptyMessage(HeartHandler.MSG_SHOW);
allSize--;
}
postDelayed(this,
time);
}
}
private
void
init(AttributeSet
attrs,
int
defStyleAttr)
{
final
TypedArray
a
=
getContext().obtainStyledAttributes(
attrs,
R.styleable.HeartLayout,
defStyleAttr,
0);
if
(pointx
<=
initX
&&
pointx
>=
0)
{
pointx
-=
10;
}
else
if
(pointx
>=
-initX
&&
pointx
<=
0)
{
pointx
+=
10;
}
else
pointx
=
initX;
mAnimator
=
new
PathAnimator(AbstractPathAnimator.Config.fromTypeArray(a,
initX,
textHight,
pointx,
dWidth,
dHeight));
a.recycle();
}
@Override
protected
void
onMeasure(int
widthMeasureSpec,
int
heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec,
heightMeasureSpec);
//获取本身的宽高
这里要注意,测量之后才有宽高
mWidth
=
getMeasuredWidth();
mHeight
=
getMeasuredHeight();
initX
=
mWidth
/
2
-
dWidth
/
2;
}
public
AbstractPathAnimator
getAnimator()
{
return
mAnimator;
}
public
void
setAnimator(AbstractPathAnimator
animator)
{
clearAnimation();
mAnimator
=
animator;
}
public
void
clearAnimation()
{
for
(int
i
=
0;
i
<
getChildCount();
i++)
{
getChildAt(i).clearAnimation();
}
removeAllViews();
}
private
static
int[]
drawableIds
=
new
int[]{R.drawable.heart0,
R.drawable.heart1,
R.drawable.heart2,
R.drawable.heart3,
R.drawable.heart4,
R.drawable.heart5,
R.drawable.heart6,
R.drawable.heart7,
R.drawable.heart8,};
private
Random
random
=
new
Random();
public
void
addFavor()
{
HeartView
heartView
=
new
HeartView(getContext());
heartView.setDrawable(drawableIds[random.nextInt(8)]);
init(attrs,
defStyleAttr);
mAnimator.start(heartView,
this);
}
private
long
nowTime,
lastTime;
final
static
int[]
sizeTable
=
{9,
99,
999,
9999,
99999,
999999,
9999999,
99999999,
999999999,
Integer.MAX_VALUE};
public
static
int
sizeOfInt(int
x)
{
for
(int
i
=
0;
;
i++)
if
(x
<=
sizeTable[i])
return
i
+
1;
}
public
void
addFavor(int
size)
{
switch
(sizeOfInt(size))
{
case
1:
size
=
size
%
10;
break;
default:
size
=
size
%
100;
}
if
(size
==
0)
return;
nowTime
=
System.currentTimeMillis();
long
time
=
nowTime
-
lastTime;
if
(lastTime
==
0)
time
=
2
*
1000;//第一次分为2秒显示完
time
=
time
/
(size
+
15);
if
(heartThread
==
null)
{
heartThread
=
new
HeartThread();
}
if
(heartHandler
==
null)
{
heartHandler
=
new
HeartHandler(this);
heartHandler.post(heartThread);
}
heartThread.addTask(time,
size);
lastTime
=
nowTime;
}
public
void
addHeart(int
color)
{
HeartView
heartView
=
new
HeartView(getContext());
heartView.setColor(color);
init(attrs,
defStyleAttr);
mAnimator.start(heartView,
this);
}
public
void
addHeart(int
color,
int
heartResId,
int
heartBorderResId)
{
HeartView
heartView
=
new
HeartView(getContext());
heartView.setColorAndDrawables(color,
heartResId,
heartBorderResId);
init(attrs,
defStyleAttr);
mAnimator.start(heartView,
this);
}
@Override
public
void
onClick(View
v)
{
int
i
=
v.getId();
if
(i
==
R.id.img)
{
if
(onHearLayoutListener
!=
null)
{
boolean
isAdd
=
onHearLayoutLis
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 网络安全服务训练学习通超星期末考试答案章节答案2024年
- 后浇带施工质量控制方案
- 2024年大学生党团知识竞赛题库及答案(共120题)
- 电力企业安全管理制度流程
- 文化活动环保宣传方案
- 科研机构设备安全评审方案
- 中心校心理健康教育实施方案
- 小学科技创新大赛活动方案
- 商业管理辅助行业营销策略方案
- 文化创意产业项目全过程咨询管理方案
- 养老事业2024年养老产业发展前景展望
- 30题质量检验员岗位常见面试问题含HR问题考察点及参考回答
- 基于大数据的电商平台用户行为分析系统研究与实现
- 财务管理的财务财务数字化转型
- 直线与圆的位置关系-省赛一等奖
- 妊娠期病毒性肝炎
- 知识产权法治宣传活动
- 《现代护士职业素养》课件
- 2024年度患者健康教育制度
- 聚氨酯保温板
- 小学生劳动技能培养与就业市场需求
评论
0/150
提交评论