How to create Facebook like stream animation

Hello anh em, nay cuối tuần đang ngồi giải trí tý trận đế chế kinh điển của Chim Sẻ, thấy ae like điên đảo. Facebook like nhìn khá bắt mắt, nên mình đã ngay lập tức tìm hiểu xem sẽ xử lý như thế nào. Chúng ta sẽ làm 1 app ví dụ như sau:

Đầu tiên, chúng ta sẽ tạo button màu hường bên trên bằng cách sử dụng java code: Đây là đoạn code khá quen thuộc, tạo ra 1 button, set text, set color, padding sau đó add vào Relative layout. Không có gì khó khăn ở bước này cả.

  private void createPlayBtn() {
        Button playBtn = new Button(this);
        playBtn.setText("Play Animation");
        playBtn.setTextColor(Color.WHITE);
        playBtn.setBackgroundColor(ContextCompat.getColor(this, R.color.colorAccent));
        playBtn.setPadding(10, 10, 10, 10);
        RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        rl.addRule(RelativeLayout.ALIGN_BOTTOM);
        playBtn.setLayoutParams(rl);
        drawPath.addView(playBtn);

        playBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addMultpileView();
            }
        });
    }

Tiếp thep, chúng ta tạo ra 1 hàm, làm nhiệm vụ xử lý animation khi click vào button bên trên: Đoạn code trên update lại view khi chúng ta thực hiện 1 action bằng cách sử dụng onAnimationUpdate

private void createImageView(final DrawPath drawPath, int i) {
        final ImageView imageView = new ImageView(this);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getRandomNumer(), getRandomNumer());
        imageView.setLayoutParams(layoutParams);
        imageView.setImageResource(i > 5 ? R.drawable.heart : R.drawable.thumbs_up);
        drawPath.addView(imageView);

        ValueAnimator pathAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
        pathAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            float[] point = new float[2];

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                long duration = animation.getDuration();
                float val = animation.getAnimatedFraction();
                PathMeasure pathMeasure = new PathMeasure(drawPath.getPath(), true);
                pathMeasure.getPosTan(pathMeasure.getLength() * val, point, null);
                imageView.setX(point[0]);
                imageView.setY(point[1]);

                if (val > 0.6) {  // > 0.6 - to stop animation back to reverse state
                    if (drawPath != null) {
                        drawPath.removeView(imageView);
                    }
                }
            }
        });
        pathAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (drawPath != null) {
                    drawPath.removeView(imageView);
                }
            }
        });
        pathAnimator.setDuration(2000 + getRandomDuration());
        pathAnimator.start();
    }

Tiếp theo, chúng ta tạo ra 1 class Path để vẽ lên view:

  public class DrawPath extends RelativeLayout {

        public Path mPath;
        public Paint mPaint;

        public DrawPath(Context context) {
            super(context);
            intialisePaint();
        }

        private void intialisePaint() {
            mPaint = new Paint();
            mPaint.setColor(Color.TRANSPARENT);
        }

        /**
         * return Path
         *
         * @return
         */
        private Path getPath() {
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            float width = metrics.widthPixels;
            float height = metrics.heightPixels;

            float cp25 = width * 25 / 100;  // 25 percent of width
            float cp50 = width * 50 / 100;  // 50 percent of width
            float cp75 = width * 75 / 100;  // 75 percent of width

            mPath = new Path();
            mPath.moveTo(0.0f, cp50);
            float X3 = width;
            float Y3 = cp50;

            float randomYShift = cp50 + getRandomYValue() * cp75;
            float X1 = cp25;
            float Y1 = cp25 - randomYShift;
            float X2 = cp50;
            float Y2 = cp75 + randomYShift;

            mPath.cubicTo(X1, Y1, X2, Y2, X3, Y3);
            return mPath;
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawPath(getPath(), mPaint);
        }
    }

    /**
     * get Random Number for image width and height
     * @return
     */
    public int getRandomNumer() {
        Random random = new Random();
        int randomNumber = random.nextInt(90 - 60) + 60;
        return randomNumber;
    }

    /**
     * get random duration between 2000 to 100
     * @return
     */
    public int getRandomDuration() {
        Random random = new Random();
        int randomNumber = random.nextInt(2000 - 100) + 100;
        return randomNumber;
    }

    /**
     * get random value between 1.0 to 0.1
     * @return
     */
    public float getRandomYValue() {
        Random random = new Random();
        float randomNumber = random.nextFloat() * (1.0f - 0.1f) + 0.1f;
        Log.d(TAG, "getRandomYValue: " + randomNumber);
        return randomNumber;
    }
}

Quan trọng nhất bên trên chính là hàm getPath,nó sẽ tính toán ra kiểu animation, start - end của animation. Các bạn có thể tìm hiểu thêm tại đây để hiểu rõ hơn cách vẽ đường đi của view: https://developer.android.com/reference/android/graphics/Path Hi vọng có thể giúp đỡ các bạn, có gì góp ý vui lòng comment bên dưới để cùng nhau bổ sung bài viết được tốt hơn.

Code các bạn có thể tham khảo tại: https://github.com/DroidPrashantP/FacebookLiveStreamingLikeAnimation