Android-_ Skillfully_ Imitation ant forest water drop dynamic effect, launched in the whole network

 /*
    * Treatment idea:
    *     ->Customize a ViewGroup container with forest water droplets as a whole rather than a single view
    *     ->Loop create view
    *     ->Randomly set the position for the view (randomly select from some fixed sets to ensure that the water droplets do not coincide as much as possible)
    *     ->Set an initial motion direction for the view (Note: since the motion direction of each view is different, I choose to bind the direction to the tag of the view)
    *     ->Set an initial speed for the view (similarly: bind the initial speed to the tag of the view)
    *     ->Add a view to the container and zoom the display with transparency
    *     ->Start the handler to move the view up and down (Note: Here we need to set a critical value to change the speed of the view to reach the goal of fast and slow view)
    *     ->Click view, zoom, transparency and displacement to remove water droplets
    *     ->Stop calling handler when the interface is destroyed to avoid memory leakage, null pointer and other exceptions
    * */

###Topic

In the following explanation, I will post an important part of the code, that is, the key points of thinking. Please refer to the clone project for the complete code.

  • First create the view

Create view code block:

 /**
     * Add water drop view
     */
    private void addWaterView(List<Water> waters) {
        for (int i = 0; i < waters.size(); i++) {
            final Water water = waters.get(i);
            View view = mInflater.inflate(mChildViewRes, this, false);
            TextView tvWater = view.findViewById(R.id.tv_water);
            view.setTag(water);
            tvWater.setText(String.valueOf(water.getNumber()) + "g");
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    handViewClick(view);
                }
            });
            //Randomly set the direction of the view animation
            view.setTag(R.string.isUp, mRandom.nextBoolean());
            setChildViewLocation(view);
            mViews.add(view);
            addShowViewAnimation(view);
        }
    }

explain

establish view The two most important things:
 1,to view A random direction and save to view of tag in
            //Randomly set the direction of the view animation
            view.setTag(R.string.isUp, mRandom.nextBoolean());
 2,Random setting view The position of (here I don't completely random, but give some values, and then randomly select these values). Here, a new set is used to save the selected numbers. These values are excluded when selecting next time, because it's best not to completely overlap the water droplets.
/**But in fact, this is not my final method. Look down first, and colored eggs**/
 /**
     * Gets a random value on the x or y axis
     *
     * @return
     */
    private double getX_YRandom(List<Float> choseRandoms,List<Float> saveRandoms) {
        float random = 0;
        while (random == 0 || saveRandoms.contains(random)) {
            random = choseRandoms.get(mRandom.nextInt(choseRandoms.size()));
        }

        saveRandoms.add(random);
        return random;
    }
  • Animated view:
/**
     * Add display animation
     * @param view
     */
    private void addShowViewAnimation(View view) {
        addView(view);
        view.setAlpha(0);
        view.setScaleX(0);
        view.setScaleY(0);
        view.animate().alpha(1).scaleX(1).scaleY(1).setDuration(ANIMATION_SHOW_VIEW_DURATION).start();
    }

  • Next, set an initial random acceleration for the view (in fact, it is also selected randomly from the existing values, because the speed difference cannot be too large)
 /**Controls the speed of droplet animation*/
    private List<Float> mSpds = Arrays.asList(0.5f, 0.3f, 0.2f, 0.1f);
 /**
     * Set the acceleration of all sub view s
     */
    private void setViewsSpd() {
        for (int i = 0; i < mViews.size(); i++) {
            View view = mViews.get(i);
            setSpd(view);
        }
    }
 /**
     * Set spd of View
     * @param view
     */
    private void setSpd(View view) {
        float spd = mSpds.get(mRandom.nextInt(mSpds.size()));
        //Save the random displacement velocity into the tag of view. You can Baidu the two parameters setTag() method that you don't know well
        view.setTag(R.string.spd, spd);
    }
  • The next step is to start the animation and use the handler to set the offset of the view. This part is also very key, including the fast and slow processing of water droplets
  /**
     * Set offset
     */
    private void setOffSet() {
        for (int i = 0; i < mViews.size(); i++) {
            View view = mViews.get(i);
            //Get the speed of last view save
            float spd = (float) view.getTag(R.string.spd);
            //Initial position of water drop
            float original = (float) view.getTag(R.string.original_y);
            float step = spd;
            boolean isUp = (boolean) view.getTag(R.string.isUp);
            float translationY;
            //Move the view according to the up and down movement marks in the water drop tag
            if (isUp) {
                translationY = view.getY() - step;
            } else {
                translationY = view.getY() + step;
            }
            //Control of water drop displacement range
            if (translationY - original > CHANGE_RANGE) {
                translationY = original + CHANGE_RANGE;
                view.setTag(R.string.isUp, true);
            } else if (translationY - original < -CHANGE_RANGE) {
                translationY = original - CHANGE_RANGE;
                // Each time when the water drops return to the initial point, set the speed of the water drops again, so as to achieve the speed of sometimes fast and sometimes slow
                setSpd(view);
                view.setTag(R.string.isUp, false);
            }
            view.setY(translationY);
        }
    }
  • Next, the water drop disappears after clicking
  /**
     * Animation remove view
     * @param view
     */
    private void animRemoveView(final View view) {
        final float x = view.getX();
        final float y = view.getY();
        //Calculate straight line distance
        float space = getDistance(new Point((int) x, (int) y), mDestroyPoint);

        ValueAnimator animator = ValueAnimator.ofFloat(x, 0);
        //Calculate animation execution time based on distance
        animator.setDuration((long) (REMOVE_DELAY_MILLIS / mMaxSpace * space));
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                if (isCancelAnimtion) {
                    return;
                }
                float value = (float) valueAnimator.getAnimatedValue();
                float alpha = value / x;
                float translationY = y + (x - value) * (maxY - y) / x;
                setViewProperty(view, alpha, translationY, value);
            }
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //Remove water droplets from the container at the end
                removeView(view);
            }
        });
        animator.start();
    }

    /**
     * Set the properties of the view
     * @param view
     * @param alpha
     * @param translationY
     * @param translationX
     */
    private void setViewProperty(View view, float alpha, float translationY, float translationX) {
        view.setTranslationY(translationY);
        view.setTranslationX(translationX);
        view.setAlpha(alpha);
        view.setScaleY(alpha);
        view.setScaleX(alpha);
    }
  • Processing interface destroy
 /**
     * Callback when interface is destroyed
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        onDestroy();
    }

 /**
     * Destroy
     */
    private void onDestroy() {
        isCancelAnimtion = true;
        mHandler.removeCallbacksAndMessages(this);
    }

 @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //Identify whether to exit according to iscancelanimition to prevent changing the UI again when the interface is destroyed
            if (isCancelAnimtion) {
                return;
            }
            setOffSet();
            mHandler.sendEmptyMessageDelayed(WHAT_ADD_PROGRESS, PROGRESS_DELAY_MILLIS);
        }
    };

Here, the dynamic effect is finished, and the operation can reach the desired appearance, but my work is not finished. Open the profiler and look at the OMG. The memory increases sharply at the place where the view is initialized. A little more (10) cards will be used. It seems that it is still optimized

Summary:

All walks of life will eliminate some people with poor ability, not just the IT industry. Therefore, don't be intimidated by such topics as the program ape eating youth food, and don't feel that if you find a job, you will enjoy a comfortable life. While you are comfortable, others are struggling to move forward, so the gap with others will be more and more distant. Come on, hope, Each of us, become better ourselves.

Keywords: Android Design Pattern

Added by JasonHarper on Fri, 17 Dec 2021 12:57:17 +0200