Android仿每日优鲜购物车动画效果
目录

前言
实现效果
小图

圆形大图(仿每日优鲜)

使用方法
public class AnimManager {private WeakReference<Activity> mActivity;private AnimListener mListener;private long time;private final View startView;private final View endView;private final String imageUrl;private View animView;private double scale;private float animWidth;private float animHeight;private ViewGroup animMaskLayout;private AnimModule animModule = AnimModule.SMALL;private AnimManager() {this(new Builder());}AnimManager(Builder builder) {this.mActivity = builder.activity;this.startView = builder.startView;this.endView = builder.endView;this.time = builder.time;this.mListener = builder.listener;this.animView = builder.animView;this.imageUrl = builder.imageUrl;this.scale = builder.scale;this.animWidth = builder.animWidth;this.animHeight = builder.animHeight;this.animModule = builder.animModule;}/*** 开始动画*/public void startAnim() {if (startView == null || endView == null) {throw new NullPointerException("startView or endView must not null");}int[] startLocation = new int[2];int[] endLocation = new int[2];startView.getLocationInWindow(startLocation);endView.getLocationInWindow(endLocation);if (animView != null) {setAnim(startLocation, endLocation);} else if (!TextUtils.isEmpty(imageUrl)) {createImageAndAnim(startLocation, endLocation);}}private void createImageAndAnim(final int[] startLocation, final int[] endLocation) {if(animModule == AnimModule.SMALL){final ImageView animImageView = new ImageView(getActivity());LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ConvertUtils.dp2px(animWidth),ConvertUtils.dp2px(animHeight));animImageView.setLayoutParams(layoutParams);Glide.with(getActivity()).load(imageUrl).asBitmap().listener(new RequestListener<String, Bitmap>() {@Overridepublic boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {return false;}@Overridepublic boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {setAnim(animImageView, startLocation, endLocation);return false;}}).into(animImageView);}else {if (startView != null) {final CircleImageView circleImageView = new CircleImageView(getActivity());// ViewGroup.LayoutParams starViewtLayoutParams = startView.getLayoutParams();int min = Math.min(startView.getMeasuredWidth(), startView.getMeasuredHeight());LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(min,min);circleImageView.setBorderColor(Color.WHITE);circleImageView.setBorderWidth(3);circleImageView.setLayoutParams(layoutParams);Glide.with(getActivity()).load(imageUrl).asBitmap().listener(new RequestListener<String, Bitmap>() {@Overridepublic boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {return false;}@Overridepublic boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {setAnim(circleImageView, startLocation, endLocation);return false;}}).into(circleImageView);}}}private void setAnim(int[] startLocation, int[] endLocation) {setAnim(animView, startLocation, endLocation);}private void setAnim(final View v, int[] startLocation, int[] endLocation) {animMaskLayout = createAnimLayout(getActivity());// 把动画小球添加到动画层animMaskLayout.addView(v);final View view = addViewToAnimLayout(v, startLocation);//终点位置int endX = endLocation[0] - startLocation[0] + endView.getMeasuredWidth()/2;// 动画位移的y坐标int endY = endLocation[1] - startLocation[1] + 10;TranslateAnimation translateAnimationX = new TranslateAnimation(0, endX, 0, 0);translateAnimationX.setInterpolator(new AccelerateInterpolator());// 动画重复执行的次数translateAnimationX.setRepeatCount(0);translateAnimationX.setFillAfter(true);TranslateAnimation translateAnimationY = new TranslateAnimation(0, 0, 0, endY);translateAnimationY.setInterpolator(new AccelerateInterpolator());translateAnimationY.setRepeatCount(0);translateAnimationX.setFillAfter(true);AnimationSet set = new AnimationSet(false);set.setFillAfter(false);if(animModule == AnimModule.BIG_CIRCLE){ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.1f, 1.0f, 0.1f);scaleAnimation.setInterpolator(new AccelerateInterpolator());scaleAnimation.setRepeatCount(0);scaleAnimation.setFillAfter(true);set.addAnimation(scaleAnimation);}set.addAnimation(translateAnimationY);set.addAnimation(translateAnimationX);if (scale == 1) {// 计算屏幕最远两个点的直线距离double diagonalDef = Math.sqrt(Math.pow(ScreenUtils.getScreenWidth(), 2) + Math.pow(ScreenUtils.getScreenHeight(), 2));// 计算实际两点的距离double diagonal = Math.abs(Math.sqrt(Math.pow(startLocation[0] - endLocation[0], 2) + Math.pow(startLocation[1] - endLocation[1], 2)));// 计算一个值,不同距离动画执行的时间不同scale = diagonal / diagonalDef;}// 动画的执行时间,计算出的时间小于300ms默认为300msset.setDuration((time * scale) < 1000 ? 1000 : (long) (time * scale));view.startAnimation(set);// 动画监听事件set.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {v.setVisibility(View.VISIBLE);if (mListener != null) {mListener.setAnimBegin(AnimManager.this);}}@Overridepublic void onAnimationRepeat(Animation animation) {}// 动画的结束调用的方法@Overridepublic void onAnimationEnd(Animation animation) {v.setVisibility(View.GONE);animMaskLayout.removeAllViews();if (mListener != null) {mListener.setAnimEnd(AnimManager.this);}}});}public void stopAnim() {if (animMaskLayout != null && animMaskLayout.getChildCount() > 0) {animMaskLayout.removeAllViews();}}private ViewGroup createAnimLayout(Activity mainActivity) {ViewGroup rootView = (ViewGroup) mainActivity.getWindow().getDecorView();LinearLayout animLayout = new LinearLayout(mainActivity);LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT);animLayout.setLayoutParams(lp);animLayout.setId(R.id.anim_icon);animLayout.setBackgroundResource(android.R.color.transparent);rootView.addView(animLayout);return animLayout;}private View addViewToAnimLayout(final View view, int[] location) {int x = location[0];int y = location[1];LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);lp.leftMargin = x;lp.topMargin = y;view.setLayoutParams(lp);return view;}/*** 自定义时间** @param time* @return*/public long setTime(long time) {this.time = time;return time;}private Activity getActivity() {return mActivity.get();}public void setOnAnimListener(AnimListener listener) {mListener = listener;}//回调监听public interface AnimListener {void setAnimBegin(AnimManager a);void setAnimEnd(AnimManager a);}public static final class Builder {WeakReference<Activity> activity;View startView;View endView;View animView;String imageUrl;long time;double scale;float animWidth;float animHeight;AnimListener listener;private AnimModule animModule = AnimModule.SMALL;public Builder() {this.time = 1000;this.scale = 1;this.animHeight = 25;this.animWidth = 25;}public Builder animModule(AnimModule animModule) {this.animModule = animModule;return this;}public Builder with(Activity activity) {this.activity = new WeakReference<>(activity);return this;}public Builder startView(View startView) {if (startView == null) {throw new NullPointerException("startView is null");}this.startView = startView;return this;}public Builder endView(View endView) {if (endView == null) {throw new NullPointerException("endView is null");}this.endView = endView;return this;}public Builder animView(View animView) {if (animView == null) {throw new NullPointerException("animView is null");}this.animView = animView;return this;}public Builder listener(AnimListener listener) {if (listener == null) {throw new NullPointerException("listener is null");}this.listener = listener;return this;}public Builder imageUrl(String imageUrl) {this.imageUrl = imageUrl;return this;}public Builder time(long time) {if (time <= 0) {throw new IllegalArgumentException("time must be greater than zero");}this.time = time;return this;}public Builder scale(double scale) {this.scale = scale;return this;}public Builder animWidth(float width) {if (width <= 0) {throw new IllegalArgumentException("width must be greater than zero");}this.animWidth = width;return this;}public Builder animHeight(float height) {if (height <= 0) {throw new IllegalArgumentException("height must be greater than zero");}this.animHeight = height;return this;}public AnimManager build() {return new AnimManager(this);}}public enum AnimModule{SMALL,//小的(默认)BIG_CIRCLE//大的圆形}}
animManager = new AnimManager.Builder().with(this).animModule(AnimManager.AnimModule.BIG_CIRCLE)//图片的动画模式,小的或者大的(仿每日优鲜).startView(startView)//开始位置的控件.endView(imageViewShopCar)//结束位置的控件.listener(new AnimManager.AnimListener() {@Overridepublic void setAnimBegin(AnimManager a) {}@Overridepublic void setAnimEnd(AnimManager a) {//购物车回弹动画(这里是加入购物车动画执行结束时的回调我在这里加入了购物车回弹效果,不需要的话可以去掉)TranslateAnimation anim = new TranslateAnimation(0, 0, 20, 0);anim.setInterpolator(new BounceInterpolator());anim.setDuration(700);imageViewShopCar.startAnimation(anim);textViewNum.setText(num+"");}}).imageUrl(animImgUrl).build();animManager.startAnim();
源码地址:
https://github.com/myml666/ShopCarAnim
评论
