Android一点 仿淘宝购物车动画

首先看看ios上的淘宝购物车的动画效果ios淘宝购物车动画

这里写图片描述

我们实现的效果
这里写图片描述

看特效是分为两个界面,一个是主view,一个是弹出层。弹出层是用dialog实现的,只是加入了弹出的动画,这里就不分析了,我们主要看主view的动画是怎么实现的,初看好像只是缩放了一点,但是又带着点其它炫耀的动画,其实也是通过旋转、偏移等动画组合的效果。看看动画具体的实现,
1、进入的动画

/**
         * 缩放xy,但是y缩放的比例比较小
         */
        ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this,"scaleX",1.0f,0.8f);
        fViewScaleXAnim.setDuration(350);
        ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",1.0f,0.9f);
        fViewScaleYAnim.setDuration(350);

        /**
         * 重点特效
         * 通过x的双重旋转
         */
        ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this, "rotationX", 0f, 10f);
        fViewRotationXAnim.setDuration(200);
        ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
        fViewResumeAnim.setDuration(150);
        fViewResumeAnim.setStartDelay(200);

        /**
         * y需要的偏移量
         */
        ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this,"translationY",0,-0.01f* height);
        fViewTransYAnim.setDuration(350);

2、退出的动画(退出动画是和进入动画相反的)

 ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this,"scaleX",0.8f,1.0f);
        fViewScaleXAnim.setDuration(350);
        ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",0.9f,1.0f);
        fViewScaleYAnim.setDuration(350);

        ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this, "rotationX", 0f, 10f);
        fViewRotationXAnim.setDuration(200);
        ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
        fViewResumeAnim.setDuration(150);
        fViewResumeAnim.setStartDelay(200);

        ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this,"translationY",-0.01f* height,0);
        fViewTransYAnim.setDuration(350);

2、下面开始封装开发我们的ShopAnimatorView(仿淘宝购物车动画View)

ShopAnimatorView.java
package com.flyjun.shopanimator.view;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.WindowManager;
import android.widget.RelativeLayout;

public class ShopAnimatorView extends RelativeLayout{

    private int width;
    private int height;

    private AnimatorSet showAnim;
    private AnimatorSet hiddenAnim;

    private onShopAnimatorListener shopAnimatorListener;

    public ShopAnimatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // TODO Auto-generated constructor stub
        this.init();
    }

    public ShopAnimatorView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        this.init();
    }

    public ShopAnimatorView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        this.init();
    }

    /**
     * 初始化操作
     */
    private void init(){

        WindowManager wm = (WindowManager) getContext()
                .getSystemService(Context.WINDOW_SERVICE);

        width = wm.getDefaultDisplay().getWidth();
        height = wm.getDefaultDisplay().getHeight();

        initShowAnim();
        initHiddenAnim();

    }

    /**
     * 进场动画
     */
    private void initShowAnim(){

        /**
         * 缩放xy,但是y缩放的比例比较小
         */
        ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this,"scaleX",1.0f,0.8f);
        fViewScaleXAnim.setDuration(350);
        ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",1.0f,0.9f);
        fViewScaleYAnim.setDuration(350);

        /**
         * 重点特效
         * 通过x的双重旋转
         */
        ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this, "rotationX", 0f, 10f);
        fViewRotationXAnim.setDuration(200);
        ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
        fViewResumeAnim.setDuration(150);
        fViewResumeAnim.setStartDelay(200);

        /**
         * y需要的偏移量
         */
        ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this,"translationY",0,-0.01f* height);
        fViewTransYAnim.setDuration(350);


        showAnim=new AnimatorSet();
        showAnim.playTogether(fViewScaleXAnim,fViewRotationXAnim,fViewResumeAnim,fViewTransYAnim,fViewScaleYAnim);

        /**
         * 动画开始时可以 显示弹出层
         */
        showAnim.addListener(new AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
                // TODO Auto-generated method stub
                if(shopAnimatorListener != null){
                    shopAnimatorListener.onShowView();
                }
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationCancel(Animator animation) {
                // TODO Auto-generated method stub

            }
        });

    }

    /**
     * 退出动画
     */
    private void initHiddenAnim(){
        ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this,"scaleX",0.8f,1.0f);
        fViewScaleXAnim.setDuration(350);
        ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",0.9f,1.0f);
        fViewScaleYAnim.setDuration(350);

        ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this, "rotationX", 0f, 10f);
        fViewRotationXAnim.setDuration(200);
        ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
        fViewResumeAnim.setDuration(150);
        fViewResumeAnim.setStartDelay(200);

        ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this,"translationY",-0.01f* height,0);
        fViewTransYAnim.setDuration(350);

        hiddenAnim=new AnimatorSet();
        hiddenAnim.playTogether(fViewScaleXAnim,fViewRotationXAnim,fViewResumeAnim,fViewTransYAnim,fViewScaleYAnim);

        /**
         * 动画开始时可以 关闭弹出层
         */
        hiddenAnim.addListener(new AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
                // TODO Auto-generated method stub
                if(shopAnimatorListener != null){
                    shopAnimatorListener.onCancelView();
                }
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationCancel(Animator animation) {
                // TODO Auto-generated method stub

            }
        });

    }

    /**
     * 开始进入动画
     */
    public void startShowAnim(){
        showAnim.start();
    }

    /**
     * 开始退出动画
     */
    public void startHiddenAnim(){
        hiddenAnim.start();
    }

    /**
     * 设置什么显示弹出层和关闭弹出层的监听器
     */
    public void setOnShopAnimatorListener(onShopAnimatorListener shopAnimatorListener){
        this.shopAnimatorListener=shopAnimatorListener;
    }

    public interface onShopAnimatorListener{
        public void onShowView();
        public void onCancelView();
    }

}

3、弹出层的封装(实现用的是dialog)

ShopAnimatorDialog.java
package com.flyjun.shopanimator.view;

import com.flyjun.shopanimator.R;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public abstract class ShopAnimatorDialog extends Dialog{

    private Context context;

    private ShopAnimatorView shopAnimatorView;

    public ShopAnimatorDialog(Context context,ShopAnimatorView shopAnimatorView) {
        super(context);
        // TODO Auto-generated constructor stub
        this.context=context;
        this.shopAnimatorView=shopAnimatorView;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        init();

    }

    private void init(){

        /**
         * 弹出的动画
         */
        getWindow().setWindowAnimations(R.style.MyDialogAnimation);

        setCanceledOnTouchOutside(false);

        /**
         * 设置在dialog关闭时恢复动画
         */
        this.setOnCancelListener(new OnCancelListener() {

            @Override
            public void onCancel(DialogInterface dialog) {
                // TODO Auto-generated method stub
                shopAnimatorView.startHiddenAnim();
            }
        });

        setContentView(getContentView());

        android.view.WindowManager.LayoutParams ll=getWindow().getAttributes();
        ll.width=WindowManager.LayoutParams.MATCH_PARENT;
        ll.gravity=Gravity.BOTTOM;
        getWindow().setAttributes(ll);

    }

    /**
     * 返回ContentView(视图view)
     * @return
     */
    public abstract View getContentView();

    public void showDialog(){
        if(!isShowing()){
            show();
        }
    }

    public void cancelDialog(){
        if(isShowing()){
            cancel();
        }
    }
}

弹出层动画

<style name="MyDialogAnimation">
        <!--进入 -->
        <item name="android:windowEnterAnimation">@anim/dialog_enter_anim</item>
        <!--退出-->
        <item name="android:windowExitAnimation">@anim/dialog_exit_anim</item>
    </style>
dialog_enter_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">  
    <translate
        android:fromYDelta="100%"
        android:toYDelta="0"
        android:duration="300"></translate> 
</set> 
dialog_exit_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">  
    <translate
        android:fromYDelta="0"
        android:toYDelta="100%"
        android:duration="300"/> 
</set>  

4、demo代码,测试的代码就变得简单了
主view的布局

<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:background="@android:color/background_dark"
    >

    <com.flyjun.shopanimator.view.ShopAnimatorView 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/shopLayout"
        android:background="@android:color/white">

        <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello" 
        android:textSize="20sp"
        />

         <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="加入购物车" 
        android:id="@+id/add"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"/>

    </com.flyjun.shopanimator.view.ShopAnimatorView>



</RelativeLayout>
MainActivity.java
package com.flyjun.shopanimator;

import com.flyjun.shopanimator.view.ShopAnimatorView;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {

    private ShopAnimatorView shopAnimatorView;

    private TestDialog testDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 隐藏标题栏
                requestWindowFeature(Window.FEATURE_NO_TITLE);
                // 隐藏状态栏
                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                        WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_main);

        this.shopAnimatorView=(ShopAnimatorView) findViewById(R.id.shopLayout);

        this.testDialog=new TestDialog(this, shopAnimatorView);

        findViewById(R.id.add).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                shopAnimatorView.startShowAnim();
                testDialog.showDialog();
            }
        });

    }

    @Override
    public void onBackPressed() {
        // TODO Auto-generated method stub
//      super.onBackPressed();

//      shopAnimatorView.startHiddenAnim();
        testDialog.cancelDialog();
    }

}

测试的弹出层

TestDialog.java
package com.flyjun.shopanimator;

import com.flyjun.shopanimator.view.ShopAnimatorDialog;
import com.flyjun.shopanimator.view.ShopAnimatorView;

import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;

public class TestDialog extends ShopAnimatorDialog{

    public TestDialog(Context context, ShopAnimatorView shopAnimatorView) {
        super(context, shopAnimatorView);
        // TODO Auto-generated constructor stub
    }

    @Override
    public View getContentView() {
        // TODO Auto-generated method stub
        return View.inflate(getContext(), R.layout.test_dialog, null);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        findViewById(R.id.close).setOnClickListener(new android.view.View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                cancelDialog();
            }
        });
    }

}

仿淘宝购物车动画完成,厉害了Flyjun哥!!!

通过ShopAnimatorView的封装和ShopAnimatorDialog弹出层的封装,对于不同的业务和界面都可以轻松的实现了

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值