View large scale animation by imitating wechat QQ

Keywords: Android Attribute less

Today, I'm going to write an article about clicking the small picture to view the zooming animation of the large picture. The effect picture is as follows:

First of all, let's talk about the idea of implementation: when you see this effect picture, you don't even need to think about it. You can use attribute animation or compensation animation to achieve it by scaling, displacement and changing transparency. First, click the small figure to jump to another Activity B to display the large figure. This Activity is transparent (because you need to see the previous interface when you click the big picture to exit the animation, the effect will be better). The location, size and image address of the small image need to be transmitted to Activity B. before performing the image magnification effect, a control with the same size and location as the small image needs to be drawn in Activity B. Then enlarge and displace the picture. When you click the large image to exit, the image will be shrunk and displaced. At the same time, the transparency of Activity B background changes from completely opaque to completely transparent.

Let's see the implementation of the specific code:

//Part code of small diagram interface

 @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.imageView:
                int []locations=new int[2];
                //Get the absolute coordinates of the control, including the height of the status bar
                imageView.getLocationOnScreen(locations);
                //Less than Android 4.4 incomplete screen
                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];
                //Get the absolute coordinates of the control, including the height of the status bar
                imageViewsqure.getLocationOnScreen(locations2);
                //Less than Android 4.4 incomplete screen
                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;
        }
    }

Here is the code of the large screen:

public class PictureActivity extends Activity {

    private ImageView imageView;
    private boolean isAnimator = true;//Whether to use attribute animation, recommended
    private ImageView smallImage;


    @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Remove activity to enter animation
        overridePendingTransition(0, 0);
        //Use the following two sentences to realize the full screen. There will be interface jitter during the transition from full screen interface to non full screen interface, so it is not used
        //Methods
        // requestWindowFeature(Window.FEATURE_NO_TITLE);
        // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        //Full screen display larger than Android 4.4 and above
       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 {
            //Before drawing, draw as like as two peas of ImageView. First hide the big picture controls. Here we use the complement animation.
            //After the animation is completed, hide the thumbnail control and display the thumbnail control. Because the animation click event is still in the original position
            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() {
        //Remove activity leave animation
        overridePendingTransition(0, 0);

        super.onPause();

    }

    @Override
    protected void onDestroy() {

        super.onDestroy();
    }
}

Here you can use the isAnimator attribute to choose whether to use attribute animation or patching animation. And this Activity should be applied as a transparent Activity. The subject of PictureActivity needs to be configured in the configuration manifest file:

   <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>

Next, let's look at the help classes for implementing Animation:

/**
 * Created by Liu xinon January 30, 2018
 */

public class PictureSacleAnimUtils {
    //position
    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;//Animation time

    /**
     * Duplicate a ImageView as like as two peas.
     * This is required for patchwork animation
     * @param activity
     * @return copy ImageView for
     */
    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;
    }

    /**
     *
     * Configure to change the size and location of the ImageView so that the location and size of the ImageView are exactly the same as the previous page
     * @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);
        //Here, the parent control of imageView is 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);

    }




    /**
     * Enter animation mending animation implementation.
     *
     * @param activity
     * @param smallImageview  Small image to scale
     * @param imageview To show the big picture of the click
     */
    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);

         // The width after zooming is the screen width, and the width ratio after zooming
        float scaleRatX = Utils.getScreenWidth(activity) / (float) width;
        //Height after scaling
        float scaleHeight=Utils.getScreenWidth(activity)*height/(float)width;
        //Height ratio after scaling
        float scaleRatY = scaleHeight / (float) height;
        //Displacement: the distance in x direction after displacement is shifted to the left by locations[0] compared with the original position
        //The offset in the y direction, you can figure it out by yourself
        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 And above
     * Enter animation attribute animation implementation
     * Attribute animation really changes the position and size of the picture, which is realized by changing the attributes of the object
     *
     * @param activity
     * @param imageview Pictures to zoom
     *
     */
    @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);//Set zoom center point
        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 And above
     * Enter animation attribute animation implementation
     * Attribute animation really changes the position and size of the picture, which is realized by changing the attributes of the object
     *
     * @param activity
     * @param  imageview Pictures to zoom
     */
    @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();

    }


    /**
     * Exit animation mending animation implementation
     * @param activity
     * @param smallImageview Small image to scale
     * @param  imageView To show the big picture of the click
     */
    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) {

            }
        });
    }

}

The above animation help class needs to use the following tool class methods:

   /**
     * Get screen width
     *
     * @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;
    }

    /**
     * Get screen height
     * Less than Android 4.4 remove status bar height
     * @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;
    }

In fact, this effect is relatively simple to achieve, which is a little trouble for android system adaptation. Another way to achieve the effect of clicking on a small image to view a large image is to use Transition. This only applies to android 5.0 and above systems. Forehead. That's it first.

Posted by el-sid on Thu, 30 Apr 2020 18:12:11 -0700