创建 Facebook Live Reactions 动画叠加

use*_*803 6 android facebook android-animation android-layout android-design-library

我目前在一个消息传递应用程序中工作,我想将新用户显示为动画飞行图标,如 facebook 实时浮动反应。任何人都可以启发我应该遵循哪个过程或任何有用的图书馆链接吗?

我已经尝试过浏览和检查一些库链接像this1this2但这些都不是类似于Facebook的实时反应包东西。示例图像

小智 11

我通过修改旧代码实现了这一点所以这是我的解决方案。您可以更改表情符号的方向和数量,也可以让它飞过或飞过任何视图。

主文件

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="top|left"
    android:orientation="vertical">


    <FrameLayout
        android:id="@+id/animation_holder"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>       
Run Code Online (Sandbox Code Playgroud)

主要活动

    package com.example.hamidraza.flyinemojis;
import android.app.Activity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.view.animation.Animation;
public class MainActivity extends Activity {
    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);
        setContentView(R.layout.activity_main);
        emoji_one();
        emoji_two();
        emoji_three();
    }
    public void flyEmoji(final int resId) {
        ZeroGravityAnimation animation = new ZeroGravityAnimation();
        animation.setCount(1);
        animation.setScalingFactor(0.2f);
        animation.setOriginationDirection(Direction.BOTTOM);
        animation.setDestinationDirection(Direction.TOP);
        animation.setImage(resId);
        animation.setAnimationListener(new Animation.AnimationListener() {
                                           @Override
                                           public void onAnimationStart(Animation animation) {

                                           }
                                           @Override
                                           public void onAnimationEnd(Animation animation) {

                                           }

                                           @Override
                                           public void onAnimationRepeat(Animation animation) {

                                           }
                                       }
        );

        ViewGroup container = findViewById(R.id.animation_holder);
        animation.play(this,container);

    }

    public void emoji_one() {
        // You can change the number of emojis that will be flying on screen
        for (int i = 0; i < 5; i++) {
            flyEmoji(R.drawable.emojis1);
        }
    }
    // You can change the number of emojis that will be flying on screen

    public void emoji_two(){
            for(int i=0;i<5;i++) {
                flyEmoji(R.drawable.dabemoji);
            }

    }
    // You can change the number of emojis that will be flying on screen

    public void emoji_three(){
        for(int i=0;i<5;i++) {
            flyEmoji(R.drawable.heart);
        }

    }


    // This method will be used if You want to fly your Emois Over any view

//    public void flyObject(final int resId, final int duration, final Direction from, final Direction to, final float scale) {
//
//        ZeroGravityAnimation animation = new ZeroGravityAnimation();
//        animation.setCount(1);
//        animation.setScalingFactor(scale);
//        animation.setOriginationDirection(from);
//        animation.setDestinationDirection(to);
//        animation.setImage(resId);
//        animation.setDuration(duration);
//        animation.setAnimationListener(new Animation.AnimationListener() {
//            @Override
//            public void onAnimationStart(Animation animation) {
//
//            }
//
//            @Override
//            public void onAnimationEnd(Animation animation) {
//
//                flyObject(resId, duration, from, to, scale);
//            }
//
//            @Override
//            public void onAnimationRepeat(Animation animation) {
//
//            }
//        });
//
//        ViewGroup container = (ViewGroup) findViewById(R.id.animation_bigger_objects_holder);
//        animation.play(this,container);
//
//    }
//

}        
Run Code Online (Sandbox Code Playgroud)

零重力动画

   package com.example.hamidraza.flyinemojis;


import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;


public class ZeroGravityAnimation {

    private static final int RANDOM_DURATION = -1;



    private Direction mOriginationDirection = Direction.RANDOM;
    private Direction mDestinationDirection = Direction.RANDOM;
    private int mDuration = RANDOM_DURATION;
    private int mCount = 1;
    private int mImageResId;
    private float mScalingFactor = 1f;
    private Animation.AnimationListener mAnimationListener;


    /**
     * Sets the orignal direction. The animation will originate from the given direction.

     */
    public ZeroGravityAnimation setOriginationDirection(Direction direction) {
        this.mOriginationDirection = direction;
        return this;
    }

    /**
     * Sets the animation destination direction. The translate animation will proceed towards the given direction.
     * @param direction
     * @return
     */
    public ZeroGravityAnimation setDestinationDirection(Direction direction) {
        this.mDestinationDirection = direction;
        return this;
    }

    /**
     * Will take a random time duriation for the animation
     * @return
     */
    public ZeroGravityAnimation setRandomDuration() {
        return setDuration(RANDOM_DURATION);
    }

    /**
     * Sets the time duration in millseconds for animation to proceed.
     * @param duration
     * @return
     */
    public ZeroGravityAnimation setDuration(int duration) {
        this.mDuration = duration;
        return this;
    }

    /**
     * Sets the image reference id for drawing the image
     * @param resId
     * @return
     */
    public ZeroGravityAnimation setImage(int resId) {
        this.mImageResId = resId;
        return this;
    }

    /**
     * Sets the image scaling value.
     * @param scale
     * @return
     */
    public ZeroGravityAnimation setScalingFactor(float scale) {
        this.mScalingFactor = scale;
        return this;
    }

    public ZeroGravityAnimation setAnimationListener(Animation.AnimationListener listener) {
        this.mAnimationListener = listener;
        return this;
    }

    public ZeroGravityAnimation setCount(int count) {
        this.mCount = count;
        return this;
    }


    /**
     * Starts the Zero gravity animation by creating an OTT and attach it to th given ViewGroup
     * @param activity
     * @param ottParent
     */
    public void play(Activity activity, ViewGroup ottParent) {

        DirectionGenerator generator = new DirectionGenerator();

        if(mCount > 0) {

            for (int i = 0; i < mCount; i++) {


                final int iDupe = i;

                Direction origin = mOriginationDirection == Direction.RANDOM ? generator.getRandomDirection() : mOriginationDirection;
                Direction destination = mDestinationDirection == Direction.RANDOM ? generator.getRandomDirection(origin) : mDestinationDirection;

                int startingPoints[] = generator.getPointsInDirection(activity, origin);
                int endPoints[] = generator.getPointsInDirection(activity,destination);


                Bitmap bitmap = BitmapFactory.decodeResource(activity.getResources(), mImageResId);

                Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() * mScalingFactor), (int) (bitmap.getHeight() * mScalingFactor), false);

                switch (origin) {
                    case LEFT:
                        startingPoints[0] -= scaledBitmap.getWidth();
                        break;

                    case RIGHT:
                        startingPoints[0] += scaledBitmap.getWidth();
                        break;

                    case TOP:
                        startingPoints[1] -= scaledBitmap.getHeight();
                        break;
                    case BOTTOM:
                        startingPoints[1] += scaledBitmap.getHeight();
                        break;
                }

                switch (destination) {
                    case LEFT:
                        endPoints[0] -= scaledBitmap.getWidth();
                        break;

                    case RIGHT:
                        endPoints[0] += scaledBitmap.getWidth();
                        break;

                    case TOP:
                        endPoints[1] -= scaledBitmap.getHeight();
                        break;
                    case BOTTOM:
                        endPoints[1] += scaledBitmap.getHeight();
                        break;
                }


                final OverTheTopLayer layer = new OverTheTopLayer();

                FrameLayout ottLayout = layer.with(activity)
                        .scale(mScalingFactor)
                        .attachTo(ottParent)
                        .setBitmap(scaledBitmap, startingPoints)
                        .create();


                switch (origin) {
                    case LEFT:

                }

                int deltaX = endPoints[0]  - startingPoints[0];
                int deltaY = endPoints[1] - startingPoints[1];

                int duration = mDuration;
                if (duration == RANDOM_DURATION) {
                    duration = RandomUtil.generateRandomBetween(3500, 12500);
                }

                TranslateAnimation animation = new TranslateAnimation(0, deltaX, 0, deltaY);
                animation.setDuration(duration);
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {

                        if (iDupe == 0) {
                            if (mAnimationListener != null) {
                                mAnimationListener.onAnimationStart(animation);
                            }
                        }
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {

                        layer.destroy();

                        if (iDupe == (mCount - 1)) {
                            if (mAnimationListener != null) {
                                mAnimationListener.onAnimationEnd(animation);
                            }
                        }

                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });
                layer.applyAnimation(animation);
            }
        }
        else  {

            Log.e(ZeroGravityAnimation.class.getSimpleName(),"Count was not provided, animation was not started");
        }
    }

    /**
     * Takes the content view as view parent for laying the animation objects and starts the animation.
     * @param activity - activity on which the zero gravity animation should take place.
     */
    public void play(Activity activity) {

        play(activity,null);

    }
}
Run Code Online (Sandbox Code Playgroud)

RandomUtils Java 类

package com.example.hamidraza.flyinemojis;

import java.util.Random;


public class RandomUtil {

    /**
     * Generates the random between two given integers.
     */
    public static int generateRandomBetween(int start, int end) {

        Random random = new Random();
        int rand = random.nextInt(Integer.MAX_VALUE - 1) % end;

        if (rand < start) {
            rand = start;
        }
        return rand;
    }
}
Run Code Online (Sandbox Code Playgroud)

方向

     package com.example.hamidraza.flyinemojis;
    
    
    
    public enum Direction {
    
        TOP, LEFT, RIGHT, BOTTOM,RANDOM
    }
Run Code Online (Sandbox Code Playgroud)

方向发生器

    package com.example.hamidraza.flyinemojis;
import android.app.Activity;
import java.util.Random;
public class DirectionGenerator {


    /**
     * Gets the random pixel points in the given direction of the screen
     * @param activity - activity from where you are referring the random value.
     * @param direction - on among LEFT,RIGHT,TOP,BOTTOM,RANDOM
     * @return a pixel point {x,y} in the given direction.
     */
    public int[] getPointsInDirection(Activity activity, Direction direction) {

        switch (direction) {

            case LEFT:
                return getRandomLeft(activity);
            case RIGHT:
                return getRandomRight(activity);
            case BOTTOM:
                return getRandomBottom(activity);
            case TOP:
                return getRandomTop(activity);

            default:
                Direction[] allDirections = new Direction[]{Direction.LEFT,Direction.TOP,Direction.BOTTOM,Direction.RIGHT};
                int index = new Random().nextInt(allDirections.length);
                return getPointsInDirection(activity, allDirections[index]);

        }

    }

    /**
     * Gets the random pixel points in the left direction of the screen. The value will be of {0,y} where y will be a random value.
     * @param activity - activity from where you are referring the random value.
     * @return a pixel point {x,y}.
     */
    public int[] getRandomLeft(Activity activity) {

        int x = 0;

        int height = activity.getResources().getDisplayMetrics().heightPixels;

        Random random = new Random();
        int y = random.nextInt(height);

        return new int[]{x, y};
    }

    /**
     * Gets the random pixel points in the top direction of the screen. The value will be of {x,0} where x will be a random value.
     * @param activity - activity from where you are referring the random value.
     * @return a pixel point {x,y}.
     */
    public int[] getRandomTop(Activity activity) {

        int y = 0;

        int width = activity.getResources().getDisplayMetrics().widthPixels;

        Random random = new Random();
        int x = random.nextInt(width);

        return new int[]{x, y};
    }

    /**
     * Gets the random pixel points in the right direction of the screen. The value will be of {screen_width,y} where y will be a random value.
     * @param activity - activity from where you are referring the random value.
     * @return a pixel point {x,y}.
     */
    public int[] getRandomRight(Activity activity) {


        int width = activity.getResources().getDisplayMetrics().widthPixels;
        int height = activity.getResources().getDisplayMetrics().heightPixels;

        int x = width ;

        Random random = new Random();
        int y = random.nextInt(height);

        return new int[]{x, y};
    }

    /**
     * Gets the random pixel points in the bottom direction of the screen. The value will be of {x,screen_height} where x will be a random value.
     * @param activity - activity from where you are referring the random value.
     * @return a pixel point {x,y}.
     */
    public int[] getRandomBottom(Activity activity) {


        int width = activity.getResources().getDisplayMetrics().widthPixels;
        int height = activity.getResources().getDisplayMetrics().heightPixels;


        int y = height ;
        Random random = new Random();
        int x = random.nextInt(width);

        return new int[]{x, y};
    }

    /**
     * Gets a random direction.
     * @return one among LEFT,RIGHT,BOTTOM,TOP
     */
    public Direction getRandomDirection() {
        Direction[] allDirections = new Direction[]{Direction.LEFT,Direction.TOP,Direction.BOTTOM,Direction.RIGHT};
        int index = new Random().nextInt(allDirections.length);
        return (allDirections[index]);
    }

    /**
     * Gets a random direction skipping the given direction.
     * @param toSkip a direction which should not be returned by this method.
     * @return one among LEFT,RIGHT,BOTTOM if TOP is provided as direction to skip,
     * one among TOP,RIGHT,BOTTOM if LEFT is provided as direction to skip
     * and so on.
     */
    public Direction getRandomDirection(Direction toSkip) {
        Direction[] allExceptionalDirections;
        switch (toSkip) {

            case LEFT:
                allExceptionalDirections = new Direction[]{Direction.TOP,Direction.BOTTOM,Direction.RIGHT};
                break;
            case RIGHT:
                allExceptionalDirections = new Direction[]{Direction.TOP,Direction.BOTTOM,Direction.LEFT};
                break;
            case BOTTOM:
                allExceptionalDirections = new Direction[]{Direction.TOP,Direction.LEFT,Direction.RIGHT};
                break;
            case TOP:
                allExceptionalDirections = new Direction[]{Direction.LEFT,Direction.BOTTOM,Direction.RIGHT};
                break;

            default:
                allExceptionalDirections = new Direction[]{Direction.LEFT,Direction.TOP,Direction.BOTTOM,Direction.RIGHT};


        }

        int index = new Random().nextInt(allExceptionalDirections.length);
        return (allExceptionalDirections[index]);
    }
}
Run Code Online (Sandbox Code Playgroud)

OverTheTopLayer 这将有助于在某些视图上飞行表情符号

    package com.example.hamidraza.flyinemojis;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.FrameLayout;
import android.widget.ImageView;

import java.lang.ref.WeakReference;


public class OverTheTopLayer {

    public static class OverTheTopLayerException extends RuntimeException {
        public OverTheTopLayerException(String msg) {
            super(msg);
        }
    }

    private WeakReference<Activity> mWeakActivity;
    private WeakReference<ViewGroup> mWeakRootView;
    private FrameLayout mCreatedOttLayer;
    private float mScalingFactor = 1.0f;
    private int[] mDrawLocation = {0, 0};
    private Bitmap mBitmap;


    public OverTheTopLayer() {
    }

    /**
     * To create a layer on the top of activity

     */
    public OverTheTopLayer with(Activity weakReferenceActivity) {
        mWeakActivity = new WeakReference<Activity>(weakReferenceActivity);
        return this;
    }

    /**
     * Draws the image as per the drawable resource id on the given location pixels.

     */
    public OverTheTopLayer generateBitmap(Resources resources, int drawableResId, float mScalingFactor, int[] location) {

        if (location == null) {
            location = new int[]{0, 0};
        } else if (location.length != 2) {
            throw new OverTheTopLayerException("Requires location as an array of length 2 - [x,y]");
        }

        Bitmap bitmap = BitmapFactory.decodeResource(resources, drawableResId);

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() * mScalingFactor), (int) (bitmap.getHeight() * mScalingFactor), false);

        this.mBitmap = scaledBitmap;

        this.mDrawLocation = location;
        return this;
    }

    public OverTheTopLayer setBitmap(Bitmap bitmap, int[] location) {

        if (location == null) {
            location = new int[]{0, 0};
        } else if (location.length != 2) {
            throw new OverTheTopLayerException("Requires location as an array of length 2 - [x,y]");
        }

        this.mBitmap = bitmap;
        this.mDrawLocation = location;
        return this;
    }


    /**
     * Holds the scaling factor for the image.
     *
     * @param scale
     * @return
     */
    public OverTheTopLayer scale(float scale) {

        if (scale <= 0) {
            throw new OverTheTopLayerException("Scaling should be > 0");

        }
        this.mS


小智 1

我也问了你同样的问题,但我没有找到类似的 Android 的东西,所以我决定自己做。

我在 Android Studio 中创建了这个项目,我基于我在 YouTube 上找到的 Swift 教程,您可以通过单击此处查看它。

我使用该类Path绘制了气泡或图像 ( ImageView) 所遵循的路径,并ObjectAnimator通过该路径初始化动画。

最后,我对Rand路径的值进行了随机化,使其外观与 Facebook Live 更加相似,而不仅仅是让所有气泡或图像都遵循相同的路径。

这是我的项目在 Android Studio 中演示的视频:这里!