仿微信QQ查看大图缩放动画

今天来写一篇关于点击小图查看大图的缩放动画的文章,效果图如下所示:
效果图

先来讲一下实现的思路:看到这个效果图,想都不用想就知道用属性动画或者补间动画通过缩放、位移、改变透明度来实现。首先点击小图会跳转到另一个Activity B来显示大图。这个Activity是透明的Activity(因为点击大图执行退出动画时,需要看到上一个界面,效果才更佳)。需要传小图的位置、大小、图片地址三个信息给Activity B,执行图片放大效果前,需要在Activity B中绘制一个和小图大小位置一样的控件。再对图片进行放大和位移。点击大图退出时,对图片进行缩小和位移。同时对Activity B背景透明度从完全不透明到完全透明改变。

下面看一下具体代码的实现:

//小图界面部分代码

 @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.imageView:
                int []locations=new int[2];
                //获取控件的绝对坐标包括状态栏高度
                imageView.getLocationOnScreen(locations);
                //小于android4.4 不全屏
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.KITKAT) {
                    locations[1] = locations[1] - Utils.getStatusBarHeight(this);
                }
                String uri=Utils.testImageUrl;
                PictureActivity.startActivity(this,locations,imageView.getWidth(),imageView.getHeight(),uri);
                break;
            case R.id.imageView2:
                int []locations2=new int[2];
                //获取控件的绝对坐标包括状态栏高度
                imageViewsqure.getLocationOnScreen(locations2);
                //小于android4.4 不全屏
                if(Build.VERSION.SDK_INT<Build.VERSION_CODES.KITKAT) {
                    locations2[1] = locations2[1] - Utils.getStatusBarHeight(this);
                }
                String uri2=Utils.testImageUrl2;
                PictureActivity.startActivity(this,locations2,imageViewsqure.getWidth(),imageViewsqure.getHeight(),uri2);
                break;
        }
    }

下面是大图界面的代码:

public class PictureActivity extends Activity {

    private ImageView imageView;
    private boolean isAnimator = true;//是不是使用属性动画,推荐
    private ImageView smallImage;


    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //去除activity进入动画
        overridePendingTransition(0, 0);
        //使用下面两句实现全屏,在全屏界面过渡到非全屏界面会有界面抖动问题,所以没有用这
        //种方法
        // requestWindowFeature(Window.FEATURE_NO_TITLE);
        // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        //大于android4.4及以上全屏显示
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                getWindow().setStatusBarColor(Color.TRANSPARENT);
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                getWindow()
                        .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            }
        }

        setContentView(R.layout.activity_picture);


        imageView = (ImageView) findViewById(R.id.imageView);


        if (isAnimator) {
            PictureSacleAnimUtils.setUpImageView(this, imageView);
           PictureSacleAnimUtils.enterAnimator(this, imageView);
        } else {
            //在动画前先绘制一个一模一样的ImageView,先把大图控件隐藏,这里用补间动画 ,
            //动画完成后隐藏小图控件,显示大图控件。因为补间动画点击事件还是在原来的位置
            smallImage = PictureSacleAnimUtils.copyImageView(this);
            imageView.setVisibility(View.GONE);
           PictureSacleAnimUtils.enterAnimation(this, smallImage, imageView);
        }

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isAnimator) {
                    PictureSacleAnimUtils.exitAnimator(PictureActivity.this, imageView);
                } else {
                    PictureSacleAnimUtils.exitAnimation(PictureActivity.this, smallImage, imageView);
                }

            }
        });


    }

    public static void startActivity(Context context, int[] locations, int width, int height, String url) {
        Intent intent = new Intent(context, PictureActivity.class);
        intent.putExtra(PictureSacleAnimUtils.LOCATIONS, locations);
        intent.putExtra(PictureSacleAnimUtils.WIDTH, width);
        intent.putExtra(PictureSacleAnimUtils.HEIGHT, height);
        if (!TextUtils.isEmpty(url)) {
            intent.putExtra(PictureSacleAnimUtils.PICTUREURI, url);
        }
        context.startActivity(intent);
    }

    @Override
    protected void onPause() {
        //去除activity离开动画
        overridePendingTransition(0, 0);

        super.onPause();

    }

    @Override
    protected void onDestroy() {

        super.onDestroy();
    }
}

这里可以 isAnimator属性来选择是否使用属性动画还是补间动画。而且这个Activity要应用为透明Activity。需要在配置清单文件中配置PictureActivity的主题:

   <style name="TranslucentTheme">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowIsTranslucent">true</item>

        <item name="android:windowNoTitle">true</item>

        <item name="android:windowContentOverlay">@null</item>
    </style>

接下来我们来看看实现动画的帮助类:


/**
 * Created by 刘信 on 2018/1/30.
 */

public class PictureSacleAnimUtils {
    //位置
    public static final String LOCATIONS = "locations";
    public static final String WIDTH = "width";
    public static final String HEIGHT = "height";
    public static final String PICTUREURI = "picture_uri";

    private static final int DURATION=300;//动画时间

    /**
     * 复制一个一模一样的ImageView
     * 补间动画需要这个
     * @param activity
     * @return copy的ImageView
     */
    public static ImageView copyImageView(Activity activity) {
        Intent intent = activity.getIntent();
        int[] locations = intent.getIntArrayExtra(LOCATIONS);
        int width = intent.getIntExtra(WIDTH, 0);
        int height = intent.getIntExtra(HEIGHT, 0);
        String url = intent.getStringExtra(PICTUREURI);
        View view = activity.getWindow().getDecorView().findViewById(android.R.id.content);
        ImageView imageCopy = new ImageView(activity);
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height);
        layoutParams.leftMargin = locations[0];
        layoutParams.topMargin = locations[1];
        imageCopy.setLayoutParams(layoutParams);
        Glide.with(activity.getApplicationContext())
                .load(url)
                .override(width, height)
                .into(imageCopy);
        ((ViewGroup) view).addView(imageCopy);
        return imageCopy;
    }

    /**
     *
     * 配置重新改变ImageView的大小和位置,使ImageView位置和大小和上个页面完全一致
     * @param activity
     */
    public static void  setUpImageView(Activity activity,ImageView imageView){
        Intent intent = activity.getIntent();
        int[] locations = intent.getIntArrayExtra(LOCATIONS);
        int width = intent.getIntExtra(WIDTH, 0);
        int height = intent.getIntExtra(HEIGHT, 0);
        String url = intent.getStringExtra(PICTUREURI);
        //这里imageView的父控件是FrameLayout
        FrameLayout.LayoutParams layoutParams=new FrameLayout.LayoutParams(width,height);
        layoutParams.leftMargin=locations[0];
        layoutParams.topMargin=locations[1];
        imageView.setLayoutParams(layoutParams);
        Glide.with(activity.getApplicationContext())
                .load(url)
                .override(width, height)
                .into(imageView);

    }




    /**
     * 进入动画 补间动画实现。
     *
     * @param activity
     * @param smallImageview  要缩放的小图
     * @param imageview 要展示点击的大图
     */
    public static void enterAnimation(final Activity activity, final ImageView smallImageview, final ImageView imageview) {
        Intent intent = activity.getIntent();
        int[] locations = intent.getIntArrayExtra(LOCATIONS);
        int width = intent.getIntExtra(WIDTH, 0);
        int height = intent.getIntExtra(HEIGHT, 0);
        final String url = intent.getStringExtra(PICTUREURI);

         // 缩放后宽度是屏幕宽度,缩放后的宽度比
        float scaleRatX = Utils.getScreenWidth(activity) / (float) width;
        //缩放后的高度
        float scaleHeight=Utils.getScreenWidth(activity)*height/(float)width;
        //缩放后的高度比
        float scaleRatY = scaleHeight / (float) height;
        //位移,位移后x方向的距离比原来位置向左偏移了locations[0]
        //y方向的偏移量,自己画图计算你就明白了
        float translateY=locations[1]-((Utils.getScreenHeight(activity)-scaleHeight)/2.0f);
        ScaleAnimation sacleAnimation = new ScaleAnimation(1, scaleRatX, 1, scaleRatY, ScaleAnimation.RELATIVE_TO_SELF, 0, ScaleAnimation.RELATIVE_TO_SELF, 0);

        TranslateAnimation translateAnimation = new TranslateAnimation(0, -locations[0], 0, -translateY);

        View  view= activity.getWindow().getDecorView().findViewById(android.R.id.content);
        view.setBackgroundColor(Color.BLACK);
      /*  AlphaAnimation alphaAnimation=new AlphaAnimation(1f,0f);
        alphaAnimation.setFillAfter(true);
        alphaAnimation.setInterpolator(new DecelerateInterpolator());
        alphaAnimation.setDuration(DURATION);
        view.startAnimation(alphaAnimation);*/
        AnimationSet animationSet = new AnimationSet(true);
        animationSet.setDuration(DURATION);
        animationSet.setFillAfter(true);
        animationSet.addAnimation(sacleAnimation);
        animationSet.addAnimation(translateAnimation);
        smallImageview.startAnimation(animationSet);
        animationSet.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                imageview.setVisibility(View.VISIBLE);
                Glide.with(activity.getApplicationContext())
                        .load(url)
                        .into(imageview);
                smallImageview.setVisibility(View.GONE);


            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }


    /**
     * android 3.0及以上适配
     * 进入动画 属性动画实现
     * 属性动画是真正的改变了图片位置和大小,通过改变对象的属性实现
     *
     * @param activity
     * @param imageview 要缩放的图片
     *
     */
    @TargetApi(11)
    public static void enterAnimator(final Activity activity, final ImageView imageview) {
        Intent intent = activity.getIntent();
        int[] locations = intent.getIntArrayExtra(LOCATIONS);
        int width = intent.getIntExtra(WIDTH, 0);
        int height = intent.getIntExtra(HEIGHT, 0);
        final String url = intent.getStringExtra(PICTUREURI);

        float scaleRatX = Utils.getScreenWidth(activity) / (float) width;
        float scaleHeight=Utils.getScreenWidth(activity)*height/(float)width;
        float scaleRatY = scaleHeight / (float) height;
        float translateY=locations[1]-((Utils.getScreenHeight(activity)-scaleHeight)/2.0f);
        imageview.setPivotX(0);//设置缩放中心点
        imageview.setPivotY(0);
        FloatEvaluator floatEvaluator=new FloatEvaluator();
        ObjectAnimator animatorScaleX=ObjectAnimator.ofObject(imageview,"scaleX",floatEvaluator,1,scaleRatX);
        ObjectAnimator animatorScaleY=ObjectAnimator.ofObject(imageview,"scaleY",floatEvaluator,1,scaleRatY);

        ObjectAnimator animatorTranslateX=ObjectAnimator.ofObject(imageview,"translationX",floatEvaluator,0,-locations[0]);
        ObjectAnimator animatorTranslateY=ObjectAnimator.ofObject(imageview,"translationY",floatEvaluator,0,-translateY);

        View  view= activity.getWindow().getDecorView().findViewById(android.R.id.content);
        view.setBackgroundColor(Color.BLACK);
     //   ObjectAnimator animatorAlpha=ObjectAnimator.ofObject(view,"alpha",floatEvaluator,0f,1f);
       // animatorAlpha.setInterpolator(new DecelerateInterpolator());
        AnimatorSet animationSet = new AnimatorSet();
        animationSet.setDuration(DURATION);

        animationSet.playTogether(animatorScaleX,animatorScaleY,animatorTranslateX,animatorTranslateY);

        animationSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Glide.with(activity.getApplicationContext())
                        .load(url)
                        .into(imageview);

            }
        });
        animationSet.start();

    }


    /**
     * android 3.0及以上适配
     * 进入动画 属性动画实现
     * 属性动画是真正的改变了图片位置和大小,通过改变对象的属性实现
     *
     * @param activity
     * @param  imageview 要缩放的图片
     */
    @TargetApi(11)
    public static void exitAnimator(final Activity activity, final ImageView imageview) {
        Intent intent = activity.getIntent();
        int[] locations = intent.getIntArrayExtra(LOCATIONS);
        int width = intent.getIntExtra(WIDTH, 0);
        int height = intent.getIntExtra(HEIGHT, 0);
        final String url = intent.getStringExtra(PICTUREURI);

        float scaleRatX = Utils.getScreenWidth(activity) / (float) width;
        float scaleHeight=Utils.getScreenWidth(activity)*height/(float)width;
        float scaleRatY = scaleHeight / (float) height;
        float translateY=locations[1]-((Utils.getScreenHeight(activity)-scaleHeight)/2.0f);
        imageview.setPivotX(0);
        imageview.setPivotY(0);
        FloatEvaluator floatEvaluator=new FloatEvaluator();
        ObjectAnimator animatorScaleX=ObjectAnimator.ofObject(imageview,"scaleX",floatEvaluator,scaleRatX,1);
        ObjectAnimator animatorScaleY=ObjectAnimator.ofObject(imageview,"scaleY",floatEvaluator,scaleRatY,1);

        ObjectAnimator animatorTranslateX=ObjectAnimator.ofObject(imageview,"translationX",floatEvaluator,-locations[0],0);
        ObjectAnimator animatorTranslateY=ObjectAnimator.ofObject(imageview,"translationY",floatEvaluator,-translateY,0);
        final ViewGroup view= (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);

        ObjectAnimator animatorAlpha=ObjectAnimator.ofObject(view,"alpha",floatEvaluator,1f,0f);

        AnimatorSet animationSet = new AnimatorSet();
        animationSet.setDuration(DURATION);
        animatorAlpha.setStartDelay(DURATION/4);

        animationSet.playTogether(animatorScaleX,animatorScaleY,animatorTranslateX,animatorTranslateY,animatorAlpha);

        animationSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                   view.removeAllViews();
                    activity.finish();


            }
        });
        animationSet.start();

    }


    /**
     * 退出动画 补间动画实现
     * @param activity
     * @param smallImageview 要缩放的小图
     * @param  imageView 要展示点击的大图
     */
    public static void exitAnimation(final Activity activity, final ImageView smallImageview, final ImageView imageView) {
        Intent intent = activity.getIntent();
        int[] locations = intent.getIntArrayExtra(LOCATIONS);
        int width = intent.getIntExtra(WIDTH, 0);
        int height = intent.getIntExtra(HEIGHT, 0);
        final String url = intent.getStringExtra(PICTUREURI);

        float scaleRatX = Utils.getScreenWidth(activity) / (float) width;
        float scaleHeight=Utils.getScreenWidth(activity)*height/(float)width;
        float scaleRatY = scaleHeight / (float) height;
        float translateY=locations[1]-((Utils.getScreenHeight(activity)-scaleHeight)/2.0f);
        ScaleAnimation sacleAnimation = new ScaleAnimation(scaleRatX, 1, scaleRatY, 1, ScaleAnimation.RELATIVE_TO_SELF, 0, ScaleAnimation.RELATIVE_TO_SELF, 0);
        TranslateAnimation translateAnimation = new TranslateAnimation(-locations[0], 0, -translateY, 0);
       final ViewGroup  view= (ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content);
        AlphaAnimation alphaAnimation=new AlphaAnimation(1f,0f);
        alphaAnimation.setFillAfter(true);
        alphaAnimation.setDuration(DURATION);
        alphaAnimation.setStartOffset(DURATION/4);
        alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                view.removeAllViews();
                activity.finish();
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        view.startAnimation(alphaAnimation);
        AnimationSet animationSet = new AnimationSet(true);
        animationSet.setDuration(DURATION);
        animationSet.setFillAfter(true);
        animationSet.addAnimation(sacleAnimation);
        animationSet.addAnimation(translateAnimation);
        smallImageview.startAnimation(animationSet);
        animationSet.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                smallImageview.setVisibility(View.VISIBLE);
                imageView.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

}

上面动画帮助类需要用到的工具类方法如下:

   /**
     * 获得屏幕宽度
     *
     * @param context
     * @return
     */
    public static int getScreenWidth(Context context)
    {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * 获得屏幕高度
     * 小于android4.4去掉状态栏高度
     * @param context
     * @return
     */
    public static int getScreenHeight(Context context)
    {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){
            return outMetrics.heightPixels;
        }else {
            return outMetrics.heightPixels-getStatusBarHeight(context);
        }

    }

    public static int getStatusBarHeight(Context context) {
        int result = 0;
        try {
            int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
            if (resourceId > 0) {
                result = context.getResources().getDimensionPixelSize(resourceId);
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return result;
    }

其实这种效果实现起来还算简单,就是对于android 系统适配问题有点麻烦。还有一种方法来实现点击小图查看大图的效果,就是使用Transition来实现。这样只适配于android 5.0及以上系统。额。那就先这样了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值