您的位置:首页 > 移动开发 > Android开发

Android——仿QQ聊天撒花特效

2016-04-05 09:46 597 查看


实现这样的效果,你要知道贝塞尔曲线,何谓贝塞尔曲线?其实就是曲线,嘿嘿,关于曲线的概念大家可以去

Android绘图机制(二)——自定义View绘制形,圆形,三角形,扇形,椭圆,曲线,文字和图片的坐标讲解
中看下,我们这里就直接写了

1.activity_main.xml

<relativelayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

//撒花的区域

<relativelayout
android:id="@+id/rlt_animation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"></relativelayout>

<button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignparentbottom="true"
android:layout_centerhorizontal="true"
android:layout_marginbottom="23dp"
android:text="开始撒花">

</button>
</relativelayout>


2.Fllower

packagecom.lgl.test;

importandroid.graphics.Bitmap;
importandroid.graphics.Path;

importjava.io.Serializable;

publicclassFllowerimplementsSerializable{

privatestaticfinallongserialVersionUID=1L;
privateBitmapimage;
privatefloatx;
privatefloaty;
privatePathpath;
privatefloatvalue;

publicBitmapgetResId(){
returnimage;
}

publicvoidsetResId(Bitmapimg){
this.image=img;
}

publicfloatgetX(){
returnx;
}

publicvoidsetX(floatx){
this.x=x;
}

publicfloatgetY(){
returny;
}

publicvoidsetY(floaty){
this.y=y;
}

publicPathgetPath(){
returnpath;
}

publicvoidsetPath(Pathpath){
this.path=path;
}

publicfloatgetValue(){
returnvalue;
}

publicvoidsetValue(floatvalue){
this.value=value;
}

@Override
publicStringtoString(){
return"Fllower[x="+x+",y="+y+",path="+path+",value="
+value+"]";
}

}


3.FllowerAnimation
动画类


packagecom.lgl.test;

importjava.util.ArrayList;
importjava.util.List;
importjava.util.Random;

importandroid.animation.ObjectAnimator;
importandroid.animation.ValueAnimator;
importandroid.animation.ValueAnimator.AnimatorUpdateListener;
importandroid.content.Context;
importandroid.graphics.Bitmap;
importandroid.graphics.BitmapFactory;
importandroid.graphics.Canvas;
importandroid.graphics.Paint;
importandroid.graphics.Path;
importandroid.graphics.PathMeasure;
importandroid.util.Log;
importandroid.util.TypedValue;
importandroid.view.View;
importandroid.view.WindowManager;
importandroid.view.animation.AccelerateInterpolator;

/**
*撒花用到的知识点:1、android属性动画2、Path路径绘制3、贝塞尔曲线
*/
publicclassFllowerAnimationextendsViewimplementsAnimatorUpdateListener{

/**
*动画改变的属性值
*/
privatefloatphase1=0f;
privatefloatphase2=0f;
privatefloatphase3=0f;

/**
*小球集合
*/
privateList<fllower>fllowers1=newArrayList<fllower>();
privateList<fllower>fllowers2=newArrayList<fllower>();
privateList<fllower>fllowers3=newArrayList<fllower>();

/**
*动画播放的时间
*/
privateinttime=4000;
/**
*动画间隔
*/
privateintdelay=400;

int[]ylocations={-100,-50,-25,0};

/**
*资源ID
*/
//privateintresId=R.drawable.fllower_love;
publicFllowerAnimation(Contextcontext){
super(context);
init(context);
//this.resId=resId;
}

@SuppressWarnings("deprecation")
privatevoidinit(Contextcontext){
WindowManagerwm=(WindowManager)context
.getSystemService(Context.WINDOW_SERVICE);
width=wm.getDefaultDisplay().getWidth();
height=(int)(wm.getDefaultDisplay().getHeight()*3/2f);

mPaint=newPaint();
mPaint.setAntiAlias(true);
//mPaint.setStrokeWidth(2);
//mPaint.setColor(Color.BLUE);
//mPaint.setStyle(Style.STROKE);

pathMeasure=newPathMeasure();

builderFollower(fllowerCount,fllowers1);
builderFollower(fllowerCount,fllowers2);
builderFollower(fllowerCount,fllowers3);

}

/**
*宽度
*/
privateintwidth=0;
/**
*高度
*/
privateintheight=0;

/**
*曲线高度个数分割
*/
privateintquadCount=10;
/**
*曲度
*/
privatefloatintensity=0.2f;

/**
*第一批个数
*/
privateintfllowerCount=4;

/**
*创建花
*/
privatevoidbuilderFollower(intcount,List<fllower>fllowers){

intmax=(int)(width*3/4f);
intmin=(int)(width/4f);
Randomrandom=newRandom();
for(inti=0;i<count;i++){
ints=random.nextInt(max)%(max-min+1)+min;
Pathpath=newPath();
CPointCPoint=newCPoint(s,ylocations[random.nextInt(3)]);
List<cpoint>points=builderPath(CPoint);
drawFllowerPath(path,points);
Fllowerfllower=newFllower();
fllower.setPath(path);
Bitmapbitmap=BitmapFactory.decodeResource(getResources(),
R.drawable.lift_flower);
fllower.setResId(bitmap);
fllowers.add(fllower);
}

}

/**
*画曲线
*
*@parampath
*@parampoints
*/
privatevoiddrawFllowerPath(Pathpath,List<cpoint>points){
if(points.size()>1){
for(intj=0;j<points.size();j++){

CPointpoint=points.get(j);

if(j==0){
CPointnext=points.get(j+1);
point.dx=((next.x-point.x)*intensity);
point.dy=((next.y-point.y)*intensity);
}elseif(j==points.size()-1){
CPointprev=points.get(j-1);
point.dx=((point.x-prev.x)*intensity);
point.dy=((point.y-prev.y)*intensity);
}else{
CPointnext=points.get(j+1);
CPointprev=points.get(j-1);
point.dx=((next.x-prev.x)*intensity);
point.dy=((next.y-prev.y)*intensity);
}

//createthecubic-splinepath
if(j==0){
path.moveTo(point.x,point.y);
}else{
CPointprev=points.get(j-1);
path.cubicTo(prev.x+prev.dx,(prev.y+prev.dy),point.x
-point.dx,(point.y-point.dy),point.x,point.y);
}
}
}
}

/**
*曲线摇摆的幅度
*/
privateintrange=(int)TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP,70,getResources()
.getDisplayMetrics());

/**
*画路径
*
*@parampoint
*@return
*/
privateList<cpoint>builderPath(CPointpoint){
List<cpoint>points=newArrayList<cpoint>();
Randomrandom=newRandom();
for(inti=0;i<quadCount;i++){
if(i==0){
points.add(point);
}else{
CPointtmp=newCPoint(0,0);
if(random.nextInt(100)%2==0){
tmp.x=point.x+random.nextInt(range);
}else{
tmp.x=point.x-random.nextInt(range);
}
tmp.y=(int)(height/(float)quadCount*i);
points.add(tmp);
}
}
returnpoints;
}

/**
*画笔
*/
privatePaintmPaint;

/**
*测量路径的坐标位置
*/
privatePathMeasurepathMeasure=null;

@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);

drawFllower(canvas,fllowers1);
drawFllower(canvas,fllowers2);
drawFllower(canvas,fllowers3);

}

/**
*高度往上偏移量,把开始点移出屏幕顶部
*/
privatefloatdy=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
40,getResources().getDisplayMetrics());

/**
*@paramcanvas
*@paramfllowers
*/
privatevoiddrawFllower(Canvascanvas,List<fllower>fllowers){
for(Fllowerfllower:fllowers){
float[]pos=newfloat[2];
//canvas.drawPath(fllower.getPath(),mPaint);
pathMeasure.setPath(fllower.getPath(),false);
pathMeasure.getPosTan(height*fllower.getValue(),pos,null);
//canvas.drawCircle(pos[0],pos[1],10,mPaint);
canvas.drawBitmap(fllower.getResId(),pos[0],pos[1]-dy,null);
}
}

ObjectAnimatormAnimator1;
ObjectAnimatormAnimator2;
ObjectAnimatormAnimator3;

publicvoidstartAnimation(){
if(mAnimator1!=null&&mAnimator1.isRunning()){
mAnimator1.cancel();
}
mAnimator1=ObjectAnimator.ofFloat(this,"phase1",0f,1f);
mAnimator1.setDuration(time);
mAnimator1.addUpdateListener(this);

mAnimator1.start();
mAnimator1.setInterpolator(newAccelerateInterpolator(1f));

if(mAnimator2!=null&&mAnimator2.isRunning()){
mAnimator2.cancel();
}
mAnimator2=ObjectAnimator.ofFloat(this,"phase2",0f,1f);
mAnimator2.setDuration(time);
mAnimator2.addUpdateListener(this);
mAnimator2.start();
mAnimator2.setInterpolator(newAccelerateInterpolator(1f));
mAnimator2.setStartDelay(delay);

if(mAnimator3!=null&&mAnimator3.isRunning()){
mAnimator3.cancel();
}
mAnimator3=ObjectAnimator.ofFloat(this,"phase3",0f,1f);
mAnimator3.setDuration(time);
mAnimator3.addUpdateListener(this);
mAnimator3.start();
mAnimator3.setInterpolator(newAccelerateInterpolator(1f));
mAnimator3.setStartDelay(delay*2);
}

/**
*跟新小球的位置
*
*@paramvalue
*@paramfllowers
*/
privatevoidupdateValue(floatvalue,List<fllower>fllowers){
for(Fllowerfllower:fllowers){
fllower.setValue(value);
}
}

/**
*动画改变回调
*/
@Override
publicvoidonAnimationUpdate(ValueAnimatorarg0){

updateValue(getPhase1(),fllowers1);
updateValue(getPhase2(),fllowers2);
updateValue(getPhase3(),fllowers3);
Log.i(tag,getPhase1()+"");
invalidate();
}

publicfloatgetPhase1(){
returnphase1;
}

publicvoidsetPhase1(floatphase1){
this.phase1=phase1;
}

publicfloatgetPhase2(){
returnphase2;
}

publicvoidsetPhase2(floatphase2){
this.phase2=phase2;
}

publicfloatgetPhase3(){
returnphase3;
}

publicvoidsetPhase3(floatphase3){
this.phase3=phase3;
}

privateStringtag=this.getClass().getSimpleName();

privateclassCPoint{

publicfloatx=0f;
publicfloaty=0f;

/**
*x-axisdistance
*/
publicfloatdx=0f;

/**
*y-axisdistance
*/
publicfloatdy=0f;

publicCPoint(floatx,floaty){
this.x=x;
this.y=y;
}
}

}


4.MainActivity


packagecom.lgl.test;

importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.RelativeLayout;

publicclassMainActivityextendsActivity{

privateButtonbtn_start;
//撒花特效
privateRelativeLayoutrlt_animation_layout;
privateFllowerAnimationfllowerAnimation;

@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//撒花初始化
rlt_animation_layout=(RelativeLayout)findViewById(R.id.rlt_animation_layout);
rlt_animation_layout.setVisibility(View.VISIBLE);
fllowerAnimation=newFllowerAnimation(this);
RelativeLayout.LayoutParamsparams=newRelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT);
fllowerAnimation.setLayoutParams(params);
rlt_animation_layout.addView(fllowerAnimation);

btn_start=(Button)findViewById(R.id.btn_start);
btn_start.setOnClickListener(newOnClickListener(){

@Override
publicvoidonClick(Viewv){
//开始撒花
fllowerAnimation.startAnimation();
}
});
}
}





                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: