Android 貝塞爾曲線,撒花了
阿新 • • 發佈:2019-02-03
撒花了
佈局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns: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"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.df.demo.demo.MainActivity">
<com.df.demo.demo.BezierLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.df.demo.demo.BezierLayout>
</RelativeLayout>
Activity
public class BezierLayout extends RelativeLayout {
Drawable[] mDrawables=new Drawable[]{getResources().getDrawable(R.drawable.apple),
getResources().getDrawable(R.drawable.banana),getResources().getDrawable(R.drawable.love),getResources().getDrawable(R.drawable.dimon)};
private LayoutParams mParams;
private int mDrawWidth;
private int mDrawHeight;
private int mHeight;
private int mWidth;
private Random mRandom=new Random();
public BezierLayout(Context context) {
this(context,null);
}
public BezierLayout(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public BezierLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mDrawWidth=mDrawables[2].getIntrinsicWidth();
mDrawHeight=mDrawables[2].getIntrinsicHeight();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//對按下事件監聽,獲取點選的位置
if(event.getAction()== MotionEvent.ACTION_DOWN){
PointF point=new PointF();
point.set(event.getX(),event.getY());
//每點選一次新增一個禮物
addPresent(point);
return true;
}
return super.onTouchEvent(event);
}
private void addPresent(PointF point) {
mParams=new LayoutParams(mDrawWidth,mDrawHeight);
//設定左邊距為落下點-圖片寬度的一半(這是為了讓圖片的中心為落下手指位置)
mParams.leftMargin=(int)(point.x-mDrawWidth/2);
//設定上邊距為落下點-圖片高度的一半(這是為了讓圖片的中心為落下手指位置)
mParams.topMargin=(int)(point.y-mDrawHeight/2);
ImageView imageView=new ImageView(getContext());
//隨機設定圖片
imageView.setImageDrawable(mDrawables[mRandom.nextInt(4)]);
//設定動畫
AnimatorSet animatorset=getObjectAnimator(imageView,point);
animatorset.setTarget(imageView);
addView(imageView,mParams);
animatorset.start();
}
public AnimatorSet getObjectAnimator(final ImageView imageview, PointF point) {
//動畫:放大+透明度+貝塞爾曲線
//放大+透明度
ObjectAnimator scalexanimator=ObjectAnimator.ofFloat(imageview,"scaleX",0.2f,0.5f);
ObjectAnimator scaleyanimator=ObjectAnimator.ofFloat(imageview,"scaleY",0.2f,0.5f);
ObjectAnimator alphaanimator=ObjectAnimator.ofFloat(imageview,"aplpha",1.0f,0f);
AnimatorSet set=new AnimatorSet();
set.playTogether(scalexanimator,scaleyanimator,alphaanimator);
set.setDuration(1000);
//貝塞爾曲線
ValueAnimator bezierAnimator=getBezierAnimator(imageview,point);
//將放大+透明度+貝塞爾曲線三種動畫新增在一起
AnimatorSet sets=new AnimatorSet();
sets.playTogether(set,bezierAnimator);
//設定動畫的物件與時間
sets.setTarget(imageview);
sets.setDuration(3000);
return sets;
}
public ValueAnimator getBezierAnimator(final ImageView imageview,PointF point) {
//貝塞爾曲線需要四個點
//起點
PointF point0=new PointF();
point0.x=point.x-mDrawWidth/2;
point0.y=point.y-mDrawHeight/2;
//第一個中間點
final PointF point1=getTooglePoint(1,point);
//d第二個中間點
PointF point2=getTooglePoint(2,point);
//最後一個點
PointF point3=new PointF(mRandom.nextInt(mWidth),0);
BerzierValutor valutor=new BerzierValutor(point1,point2);
ValueAnimator valueAnimator=ValueAnimator.ofObject(valutor,point0,point3);
valueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point= (PointF) animation.getAnimatedValue();
imageview.setX(point.x);
imageview.setY(point.y);
imageview.setAlpha(1-animation.getAnimatedFraction());
}
});
return valueAnimator;
}
private PointF getTooglePoint(int i,PointF point) {
PointF point1=new PointF();
point1.x=mRandom.nextInt(mWidth);
int reactHeight=(int)(point.y/2);
if(i==1){
//第一個中間點,一半以下的隨機位置
point1.y=reactHeight+mRandom.nextInt(reactHeight);
}else {
//第二個中間點,一半以上的隨機位置
point1.y=mRandom.nextInt(reactHeight);
}
return point1;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth=getMeasuredWidth();
mHeight=getMeasuredHeight();
}
class BerzierValutor implements TypeEvaluator<PointF> {
private PointF mPoint1;
private PointF mpoint2;
public BerzierValutor(PointF mPoint1, PointF mpoint2) {
this.mPoint1 = mPoint1;
this.mpoint2 = mpoint2;
}
@Override
public PointF evaluate(float t, PointF startValue, PointF endValue) {
PointF pointf=new PointF();
//根據貝塞爾公式設定三次方貝塞爾曲線
pointf.x=startValue.x*(1-t)*(1-t)*(1-t)+3*mPoint1.x*t*(1-t)*(1-t)+3*mpoint2.x*t*t*(1-t)+endValue.x*t*t*t;
pointf.y=startValue.y*(1-t)*(1-t)*(1-t)+3*mPoint1.y*t*(1-t)*(1-t)+3*mpoint2.y*t*t*(1-t)+endValue.y*t*t*t;
return pointf;
}
}
}