首页 > 系统 > Android > 正文

Android 利用三阶贝塞尔曲线绘制运动轨迹的示例

2019-10-22 18:14:31
字体:
来源:转载
供稿:网友

本篇文章主要介绍了Android 利用三阶贝塞尔曲线绘制运动轨迹的示例,分享给大家,具体如下:

实现点赞效果,自定义起始点以及运动轨迹

效果图:

Android,贝塞尔曲线运动轨迹,三阶贝塞尔曲线

xml布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  android:id="@+id/rl_root"  android:layout_width="match_parent"  android:layout_height="match_parent"  tools:context="stone.wshh.com.touch.MainActivity">  <stone.wshh.com.touch.MyLoveLayout    android:layout_marginBottom="100dp"    android:layout_marginRight="15dp"    android:id="@+id/love_layout"    android:layout_width="match_parent"    android:layout_height="match_parent">  </stone.wshh.com.touch.MyLoveLayout>  <Button    android:id="@+id/bt_bottom"    android:text="begin"    android:layout_alignParentBottom="true"    android:layout_centerHorizontal="true"    android:layout_marginBottom="20dp"    android:layout_width="100dp"    android:layout_height="50dp" /></RelativeLayout>

MainActivity类:

public class MainActivity extends Activity implements View.OnClickListener{  private Button btBottom;//  private WaitNoticeDialog dialog;//  public Handler handler;  private MyLoveLayout love;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    btBottom = (Button) findViewById(R.id.bt_bottom);    love = (MyLoveLayout) findViewById(R.id.love_layout);    btBottom.setOnClickListener(this);//    handler=new IHandler(this);//    dialog = new WaitNoticeDialog(this);  }  static class IHandler extends Handler {    private WeakReference<MainActivity> ui;    IHandler(MainActivity ui) {      this.ui = new WeakReference<MainActivity>(ui);    }    @Override    public void handleMessage(Message msg) {      if(ui!=null&&ui.get()!=null){        ui.get().handleMsg(msg);      }    }  }  /**   * 线程消息处理   * @param msg   */  public void handleMsg(Message msg){    switch (msg.what) {    }  }  @Override  public void onClick(View v) {    switch (v.getId()){      case R.id.bt_bottom:        love.addHeart();        break;    }  }  @Override  protected void onDestroy() {    super.onDestroy();//    handler.removeCallbacksAndMessages(null);  }}

自定义view:MyLoveLayout

public class MyLoveLayout extends RelativeLayout {  private Drawable[] drawables;  private Interpolator[] mInterpolators;  private int dWidth, mWidth;  private int dHeight, mHeight;  private LayoutParams lp;  private Random random = new Random();  public MyLoveLayout(Context context, AttributeSet attrs) {    super(context, attrs);    //imageView位置是相对于MyLoveLayout    init();  }  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    //得到本布局的宽高    mWidth = getMeasuredWidth();    mHeight = getMeasuredHeight();  }  private void init() {    // 初始化显示的图片    drawables = new Drawable[7];    drawables[0] = getResources().getDrawable(R.drawable.heart_1);    drawables[1] = getResources().getDrawable(R.drawable.heart_2);    drawables[2] = getResources().getDrawable(R.drawable.heart_3);    drawables[3] = getResources().getDrawable(R.drawable.heart_4);    drawables[4] = getResources().getDrawable(R.drawable.heart_5);    drawables[5] = getResources().getDrawable(R.drawable.heart_6);    drawables[6] = getResources().getDrawable(R.drawable.heart_7);    // 初始化插补器    mInterpolators = new Interpolator[4];    mInterpolators[0] = new LinearInterpolator();// 线性    mInterpolators[1] = new AccelerateInterpolator();// 加速    mInterpolators[2] = new DecelerateInterpolator();// 减速    mInterpolators[3] = new AccelerateDecelerateInterpolator();// 先加速后减速    // 获取图片宽高//    dWidth = drawables[0].getIntrinsicWidth();//    dHeight = drawables[0].getIntrinsicHeight();    //手动设置宽高    dWidth = dip2px(getContext(), 40);    dHeight = dip2px(getContext(), 40);    lp = new LayoutParams(dWidth, dHeight);    //设置view控件的起始位置//    lp.addRule(CENTER_HORIZONTAL, TRUE);// 这里的TRUE 要注意 不是true    lp.addRule(ALIGN_PARENT_RIGHT, TRUE);    lp.addRule(ALIGN_PARENT_BOTTOM, TRUE);  }  /**   * dp转px值   */  private int dip2px(Context context, float dpValue) {    float scale = context.getResources().getDisplayMetrics().density;    return (int) (dpValue * scale + 0.5f);  }  /**   * 进场动画,三种同时播放   * alpha透明度 (80%-0%)   * scaleX 宽度 target(20%-100%)   * scaleY 高度   * @param target   * @return   */  private AnimatorSet getEnterAnimator(final View target) {    ObjectAnimator alpha = ObjectAnimator.ofFloat(target, View.ALPHA, 0.2f, 1f);    ObjectAnimator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X, 0.2f, 1f);    ObjectAnimator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y, 0.2f, 1f);    AnimatorSet enter = new AnimatorSet();    enter.setTarget(target);    enter.setInterpolator(new LinearInterpolator());    enter.setDuration(500).playTogether(alpha, scaleX, scaleY);    return enter;  }  private ValueAnimator getBezierValueAnimator(final View target) {    // 初始化贝塞尔估值器    //随机产生两个点,以确定一条3阶贝塞尔曲线    BezierEvaluator evaluator = new BezierEvaluator(getPointF(2), getPointF(1));    // 起点在底部中心位置,终点在底部随机一个位置,改变new PointF()中值来改变起始位置//    ValueAnimator animator = ValueAnimator.ofObject(evaluator, new PointF((mWidth - dWidth) ///        2, mHeight - dHeight), new PointF(random.nextInt(getWidth()), 0));    // 起点在右下角位置,终点在左上角位置    ValueAnimator animator = ValueAnimator.ofObject(evaluator, new PointF(mWidth - dWidth, mHeight - dHeight), new PointF(0, 0));    animator.setTarget(target);    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator valueAnimator) {        // 这里获取到贝塞尔曲线计算出来的的x y值 赋值给view 这样就能让爱心随着曲线走啦        PointF pointF = (PointF) valueAnimator.getAnimatedValue();        target.setX(pointF.x);        target.setY(pointF.y);        // alpha动画,根据运动距离改变透明度//        target.setAlpha(1 - valueAnimator.getAnimatedFraction());        target.setAlpha(1 - valueAnimator.getAnimatedFraction() + 0.3f);      }    });    animator.setDuration(3000);    return animator;  }  private PointF getPointF(int i) {    PointF pointF = new PointF();    //pointF.x,pointF.y都是随机,因此可以产生n多种轨迹    pointF.x = random.nextInt(mWidth);//0~loveLayout.Width    //为了美观,建议尽量保证P2在P1上面,那怎么做呢??    //只需要将该布局的高度分为上下两部分,让p1只能在下面部分范围内变化(1/2height~height),让p2只能在上面部分范围内变化(0~1/2height),因为坐标系是倒着的;    //0~loveLayout.Height/2    if (i == 1) {      pointF.y = random.nextInt(mHeight / 2) + mHeight / 2;//P1点Y轴坐标变化    } else if (i == 2) {//P2点Y轴坐标变化      pointF.y = random.nextInt(mHeight / 2);    }//    写死的一条轨迹//    if (i == 1) {//      pointF.x=mWidth-dWidth*2;//      pointF.y = 3*dHeight;//    } else if (i == 2) {//      pointF.x=dWidth*2;//      pointF.y = mHeight -dHeight;//    }    return pointF;  }  public void addHeart() {    final ImageView imageView = new ImageView(getContext());    // 随机选一个爱心    imageView.setImageDrawable(drawables[random.nextInt(6)]);    imageView.setLayoutParams(lp);    addView(imageView);    AnimatorSet finalSet = new AnimatorSet();    AnimatorSet enterAnimatorSet = getEnterAnimator(imageView);//入场动画    ValueAnimator bezierValueAnimator = getBezierValueAnimator(imageView);//贝塞尔曲线路径动画    finalSet.playSequentially(enterAnimatorSet, bezierValueAnimator);//    finalSet.playSequentially(bezierValueAnimator);    finalSet.setInterpolator(mInterpolators[random.nextInt(4)]);    finalSet.setTarget(imageView);    finalSet.addListener(new AnimatorListenerAdapter() {      @Override      public void onAnimationEnd(Animator animation) {        super.onAnimationEnd(animation);        removeView((imageView));//删除爱心      }    });    finalSet.start();  }}

贝塞尔估值器:BezierEvaluator

public class BezierEvaluator implements TypeEvaluator<PointF> {  private PointF mControlP1;  private PointF mControlP2;  public BezierEvaluator(PointF controlP1, PointF controlP2) {    this.mControlP1 = controlP1;    this.mControlP2 = controlP2;  }  @Override  public PointF evaluate(float time, PointF start, PointF end) {    float timeLeft = 1.0f - time;    PointF point = new PointF();    point.x = timeLeft * timeLeft * timeLeft * (start.x) + 3 * timeLeft * timeLeft * time *        (mControlP1.x) + 3 * timeLeft * time *        time * (mControlP2.x) + time * time * time * (end.x);    point.y = timeLeft * timeLeft * timeLeft * (start.y) + 3 * timeLeft * timeLeft * time *        (mControlP1.y) + 3 * timeLeft * time *        time * (mControlP2.y) + time * time * time * (end.y);    return point;  }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表