购物车特效-贝塞尔曲线动画(点击添加按钮的进候,产生抛物线动画效果)

demo效果:

l 购物车特效原理:

1.从添加按钮获取开始坐标

2.从购物车图标获取结束坐标

3.打气一个视图,添加属性动画ObjectAnimator(缩小),ValueAnimator(路线)

4.动画开始时添加该视图,动画结束删除该视图

5.运动路径使用TypeEvaluator与贝塞尔函数计算

activity布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--贝塞尔曲线动画自定义控件-->
    <custom.BezierAnim
        android:id="@+id/bezier_anim"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!--添加按钮-->
    <Button
        android:id="@+id/bt_good"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_margin="10dp"
        android:text="+" />
    <!--购物车-->
    <ImageView
        android:id="@+id/iv_cart"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:src="@drawable/cart91" />
</RelativeLayout>

移动控件布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:orientation="vertical">

    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/coin91" />

</RelativeLayout>

贝塞尔曲线动画的自定义控件编写:

public class BezierAnim extends FrameLayout {
    public BezierAnim(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public BezierAnim(Context context) {
        this(context, null, 0);
    }

    public BezierAnim(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    //PointF等价于float[]数组,里面存放的x和y的值 (point相当于int[])
    private PointF mLocation = new PointF();//这样创建出来,里面还没有值

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //获取当前父布局在界面的屏幕坐标(也就是父布局左上角坐标)
        int[] layoutLoc = new int[2];
        getLocationInWindow(layoutLoc);
        mLocation.set(layoutLoc[0], layoutLoc[1]);//将父布局左上角的值赋值给mLocation
    }

    /**
     * 开始贝塞尔动画
     *
     * @param startView    动画从哪个view开始(+号)
     * @param endView      动画在哪个view结束(购物车)
     * @param layoutIdMove 动画作用的移动控件(钱袋子的布局)
     */
    public void startCartAnim(View startView, View endView, int layoutIdMove) {
        //1,开始位置
        int[] startLoc = new int[2];
        startView.getLocationInWindow(startLoc);//获取当前view在屏幕上的坐标
        PointF startF = new PointF(startLoc[0] - mLocation.x, startLoc[1] - mLocation.y);//得到当前view相对于父布局左上角位置的坐标
        // 2,结束位置
        int[] endLoc = new int[2];
        endView.getLocationInWindow(endLoc);
        final PointF endF = new PointF(endLoc[0] - mLocation.x, endLoc[1] - mLocation.y);
        //3.移动控件。inflate()参数:作用布局,参考布局,false
        final View moveView = LayoutInflater.from(getContext()).inflate(layoutIdMove, this, false);
        //开始动画  使用属性动画合集
        AnimatorSet set = new AnimatorSet();
        //缩小动画
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(moveView, "scaleX", 1.0f, 0.1f);
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(moveView, "scaleY", 1.0f, 0.1f);
        //路径动画(baisaier曲线路径,开始坐标,结束坐标)
        ValueAnimator pathAnim = ObjectAnimator.ofObject(beisaier, startF, endF);
        pathAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //更新坐标
                PointF newPointF = (PointF) animation.getAnimatedValue();
                moveView.setX(newPointF.x);
                moveView.setY(newPointF.y);
            }
        });
        //将这些动画放入集合中
        set.playTogether(scaleXAnim, scaleYAnim, pathAnim);
        Animator.AnimatorListener listener = new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                BezierAnim.this.addView(moveView);//加入动画作用的控件
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                BezierAnim.this.removeView(moveView);//移除动画作用的控件
            }

            @Override
            public void onAnimationCancel(Animator animation) {}

            @Override
            public void onAnimationRepeat(Animator animation) {}
        };
        set.addListener(listener);//动画播放监听器
        set.setDuration(1000);  //运动时间
        set.start();            //时间
    }

    //路径计算器
    private TypeEvaluator<PointF> beisaier = new TypeEvaluator<PointF>() {
        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            //返回变化的轨迹坐标
            PointF newF = new PointF((startValue.x + endValue.x) / 2, 0);
            return BezierCurve.bezier(fraction, startValue, newF, endValue);
        }
    };
}

路径计算器:

public class BezierCurve {
    /**
     * 二次贝塞尔曲线插值
     * t:值范围from = 0, to = 1
     */
    public static PointF bezier(float t, PointF point0, PointF point1, PointF point2) {
        float oneMinusT = 1.0f - t;
        PointF point = new PointF();
        point.x = oneMinusT * oneMinusT * point0.x
                + 2 * t * oneMinusT * point1.x
                + t * t * point2.x;
        point.y = oneMinusT * oneMinusT * point0.y
                + 2 * t * oneMinusT * point1.y
                + t * t * point2.y;
        return point;
    }

    /**
     * 三次贝塞尔曲线插值
     * t:值范围from = 0, to = 1
     */
    public static PointF bezier(float t, PointF point0, PointF point1, PointF point2, PointF point3) {
        float oneMinusT = 1.0f - t;
        PointF point = new PointF();
        point.x = oneMinusT * oneMinusT * oneMinusT * (point0.x)
                + 3 * oneMinusT * oneMinusT * t * (point1.x)
                + 3 * oneMinusT * t * t * (point2.x)
                + t * t * t * (point3.x);

        point.y = oneMinusT * oneMinusT * oneMinusT * (point0.y)
                + 3 * oneMinusT * oneMinusT * t * (point1.y)
                + 3 * oneMinusT * t * t * (point2.y)
                + t * t * t * (point3.y);
        return point;
    }
}

activity开始动画:

public class CartBazierActivity extends Activity {
    @InjectView(R.id.bt_good)
    Button btGood;
    @InjectView(R.id.iv_cart)
    ImageView ivCart;
    @InjectView(R.id.bezier_anim)
    BezierAnim bezierAnim;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cart_bezier);
        ButterKnife.inject(this);
    }

    @OnClick(R.id.bt_good)
    public void bezierMove() {
        Toast.makeText(this, "添加了一件商品", Toast.LENGTH_SHORT).show();
        bezierAnim.startCartAnim(btGood, ivCart, R.layout.moveview);
    }
}

若是startView和endView不在一个界面,可以用EventBus传值

更多:http://www.jb51.net/article/95991.htm

时间: 2024-10-20 20:50:03

购物车特效-贝塞尔曲线动画(点击添加按钮的进候,产生抛物线动画效果)的相关文章

点击添加按钮添加一条记录,点击删除按钮删除本条记录

点击添加按钮添加一条记录,点击删除按钮删除本条记录,并且最多只能添加4条记录 <div class="addfee"> <div><span class="add-btn">添加</div> </div> jquery //添加删除费用,最多可添加4条 $(".add-btn").on("click", function() { var len = $(".

把商品添加到购物车的动画效果(贝塞尔曲线)

如图: 参考: Android补间动画,属性动画实现购物车添加动画 思路: 确定动画的起终点 在起终点之间使用二次贝塞尔曲线填充起终点之间的点的轨迹 设置属性动画,ValueAnimator插值器,获取中间点的坐标 将执行动画的控件的x.y坐标设为上面得到的中间点坐标 开启属性动画 当动画结束时的操作 难点: PathMeasure的使用 - getLength() - boolean getPosTan(float distance, float[] pos, float[] tan) 的理解

贝塞尔曲线开发的艺术

贝塞尔曲线开发的艺术 一句话概括贝塞尔曲线:将任意一条曲线转化为精确的数学公式. 很多绘图工具中的钢笔工具,就是典型的贝塞尔曲线的应用,这里的一个网站可以在线模拟钢笔工具的使用: http://bezier.method.ac/ 贝塞尔曲线中有一些比较关键的名词,解释如下: 数据点:通常指一条路径的起始点和终止点 控制点:控制点决定了一条路径的弯曲轨迹,根据控制点的个数,贝塞尔曲线被分为一阶贝塞尔曲线(0个控制点).二阶贝塞尔曲线(1个控制点).三阶贝塞尔曲线(2个控制点)等等. 要想对贝塞尔曲

表格添加 点击添加增加一列

改代码来源于广西省平台的uums项目中的jsp/addOrUpdate.jsp界面(使用easyui 前后端未进行分离) //在表格中,点击添加的时候,自动增加一行<table style="width:98%" id="tab" class="table table-bordered table-condensed table-striped table-hover table-responsive"> <tbody>

解决Python3.6.5+Django2.0集成xadmin后台点击添加或者内容详情报 list index out of range 的错误

一 问题说明在创建Model的时候,如果存在类型是DateTimeField的字段,则在xadmin后端管理界面里,对该Model进行添加操作的时候,会报list index out of range. 这是上篇文章创建的Model: class IDC(models.Model): name = models.CharField(max_length=64) contact = models.CharField(max_length=32) phone = models.CharField(m

Android 利用二次贝塞尔曲线模仿购物车添加物品抛物线动画

0.首先,先给出一张效果gif图. 1.贝塞尔曲线原理及相关公式参考:http://www.jianshu.com/p/c0d7ad796cee 作者:许方镇. 2.原理:计算被点击 view.购物车view 以及他们所在父容器相对于屏幕的坐标. 3.在呗点击View坐标位置 父容器通过addView 增加需要完成动画的imgview. 4.自定义估值器 通过二次贝塞尔曲线公式(2个数据点,一个控制点)完成抛物线路径上的点xy坐标计算. 5.利用属性动画 +自定义估值器 完成imgview在父容

贝塞尔曲线实现的购物车添加商品动画效果

效果图如下: 1.activity_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rly_bezier_curve_shopping_cart" android:layout_w

css贝塞尔曲线模仿饿了么购物车小球动画

在线观看贝塞尔曲线值:传送门 在线观看动画效果:传送门 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> <style> html{ widt

贝塞尔曲线实现购物车飞入效果

代码地址如下:http://www.demodashi.com/demo/12618.html 前言 做了一个模仿添加物品飞入购物车效果的例子,下面来讲讲它的简单使用 将涉及到以下内容: 工具类的使用 项目结构图与效果图 程序设计与实现 一. 工具类设计 工具类比较多代码,这里就不每个都贴出来了,如下截图为工具类 二. 工具类的使用 飞入购物车效果我封装成了一个工具类FlyAnimtor,下面讲讲它的使用. 如果你想使用飞入效果,你可以这样写: FlyAnimtor.getInstance().