本文主要参考博客,并做了一点修改:
https://blog.csdn.net/z82367825/article/details/51030866
实现一个全屏动画的效果如下:
主界面的activity.java:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//此方法为微信插件,可以在微信中自动安装应用程序
//handleApkIntent();
}
private void handleApkIntent() {
Intent intent = getIntent();
if (intent != null) {
Uri uri = intent.getData();
if (uri != null) {
String path = uri.getPath();
if (!TextUtils.isEmpty(path)) {
tryUpdate(path);
}
}
}
}
private void tryUpdate(String path) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch (Exception e) {
}
}
private void initView() {
findViewById(R.id.button_show).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FloatViewControl.getInstance().startAnimation(MainActivity.this);
}
});
findViewById(R.id.button_hide).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FloatViewControl.getInstance().stopAnimation(MainActivity.this);
}
});
}
}
动画实现的主要代码FloatView:
public class FloatView extends FlowBaseView {
/**
* 随机数
*/
private float mMinStartX;
private float mMidStartX;
private float mMaxStartX;
private float mMinStartY;
private float mMaxStartY;
private float mMinVx;
private float mMaxVx;
private float mMinVy;
private float mMaxVy;
private float mMinAccelerator;
private float mMaxAccelerator;
/**
* 当前是否有动画正在展示
*/
private boolean mIsShowing = false;
/**
* 动画产生间隔时间
*/
private static final long ANIM_INTERVAL = 600;
/**
* 动画持续时间
*/
private static final long ANIM_DURATION = 3;
/**
* 动画是否持续
*/
private boolean mIsContinue = true;
/**
* 动画集合
*/
private List mAnimatorList;
/**
* 左边和右边两个动画,目的是增加表情数量,且不重叠
*/
private static int DO_ANIM_LEFT = 1;
private static int DO_ANIM_RIGHT = 2;
/**
* 动画Handler
*/
private AnimHandler mHandler;
/**
* 动画Handler定义
*/
private static class AnimHandler extends Handler {
private WeakReference mWeakReference;
public AnimHandler(FloatView floatView) {
mWeakReference = new WeakReference(floatView);
}
@Override
public void handleMessage(Message msg) {
if (msg.what == ANIM_MSG) {
mWeakReference.get().createAnim(DO_ANIM_LEFT);
mWeakReference.get().createAnim(DO_ANIM_RIGHT);
}
}
}
/**
* 动画消息标志
*/
private static final int ANIM_MSG = 0x99;
/**
* 间隔时间产生动画
*/
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
while (mIsContinue) {
try {
Thread.sleep(ANIM_INTERVAL);
Message msg = mHandler.obtainMessage();
msg.what = ANIM_MSG;
mHandler.sendMessage(msg);
} catch (Exception e) {
}
}
}
};
public FloatView(Context context) {
super(context);
init(context);
}
public FloatView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mHandler = new AnimHandler(this);
mAnimatorList = new ArrayList();
//X轴弹出表情的起始位置
mMinStartX = 0;
mMidStartX = getScreenWidth(context) * 1 / 2;
mMaxStartX = getScreenWidth(context) * 4 / 5;
//Y轴弹出表情的起始位置
mMinStartY = -getScreenHeight(context) * 4 / 5f;
mMaxStartY = -getScreenHeight(context);
mMinVx = (getScreenWidth(context) + mMaxStartX) / ANIM_DURATION;
mMaxVx = getScreenWidth(context) * 1.2f;
mMinVy = getScreenHeight(context) / 9f;
mMaxVy = getScreenHeight(context) / 9f;
mMinAccelerator = getScreenHeight(context) / 2;
mMaxAccelerator = getScreenHeight(context) / 2;
}
/**
* start
*/
public void start() {
new Thread(mRunnable).start();
mIsShowing = true;
}
/**
* stop
*/
public void stop() {
mIsContinue = false;
mIsShowing = false;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
for (ValueAnimator animator : mAnimatorList) {
if (animator.isRunning()) {
animator.end();
}
}
mAnimatorList.clear();
}
}, 100);
}
/**
* 挂载到某个Activity的最顶层
*
* @param activity
*/
public void attachActivity(Activity activity) {
ViewParent parent = getParent();
if (parent != null && parent instanceof ViewGroup) {
ViewGroup parentView = (ViewGroup) parent;
parentView.removeView(this);
}
FrameLayout decor = (FrameLayout) activity.getWindow().getDecorView();
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
decor.addView(this, lp);
mIsShowing = true;
}
/**
* 从某个Activity移除
*
* @param activity
*/
public void disAttach(Activity activity) {
FrameLayout decor = (FrameLayout) activity.getWindow().getDecorView();
decor.removeView(this);
mIsShowing = false;
}
/**
* 是否正在展示
*
* @return
*/
public boolean isShowing() {
return mIsShowing;
}
/**
* 创建动画
*/
private void createAnim(int leftOrRight) {
//从屏幕上方进入
float startX = getRandomValue(mMinStartX, mMidStartX);
switch (leftOrRight) {
case 1:
startX = getRandomValue(mMinStartX, mMidStartX);
break;
case 2:
startX = getRandomValue(mMidStartX, mMaxStartX);
break;
}
float startY = getRandomValue(mMinStartY, mMaxStartY);
float vx = getRandomValue(mMinVx, mMaxVx);
float vy = getRandomValue(mMinVy, mMaxVy);
FloatParams params = new FloatParams(startX, startY, vx, vy, getRandomValue(mMinAccelerator, mMaxAccelerator));
ImageView view = new ImageView(getContext());
view.setBackgroundDrawable(getResources().getDrawable(R.drawable.heart_eyes));
startAnim(view, params);
}
/**
* 开始动画
*
* @param view
* @param params
*/
private void startAnim(final View view, final FloatParams params) {
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
addView(view, lp);
final ValueAnimator valueAnimator = new ValueAnimator();
mAnimatorList.add(valueAnimator);
valueAnimator.setDuration(ANIM_DURATION * 1000);
valueAnimator.setObjectValues(new PointF(params.mStartX, params.mStartY));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator() {
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue) {
PointF point = new PointF();
float t = fraction * ANIM_DURATION;
point.x = params.mStartX;
point.y = params.mStartY + params.mVy * t + 0.5f * params.mAccelerator * t;
return point;
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (mIsShowing) {
mAnimatorList.remove(valueAnimator);
removeView(view);
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
view.setX(point.x);
view.setY(-point.y);
}
});
}
/**
* Float参数
*/
private class FloatParams {
/**
* 初始的x值
*/
public float mStartX;
/**
* 初始的y值
*/
public float mStartY;
/**
* x轴速度
*/
public float mVx;
/**
* y轴速度
*/
public float mVy;
/**
* 加速度
*/
public float mAccelerator;
public FloatParams(float startX, float startY, float vx, float vy,
float accelerator) {
mStartX = startX;
mStartY = startY;
mVx = vx;
mVy = vy;
mAccelerator = accelerator;
}
}
/**
* 生成随机数
*/
private float getRandomValue(float min, float max) {
return min + (float) (Math.random() * (max - min + 1));
}
}
基础工具类FlowBaseView.java
public class FlowBaseView extends RelativeLayout {
public static float sDensity = 1.0f;
public static int sDensityDpi;
public static float sFontDensity;
public static float sScaleX = 1f;
public static float sScaleY = 1f;
/**
* 默认设计的大小为720×1080
*/
public static float sDefaultWidth = 720;
public static float sDefaultHeight = 1080;
/**
* 触摸距离
*/
public static int sTouchSlop;
public FlowBaseView(Context context) {
super(context);
resetDensity(context);
}
public FlowBaseView(Context context, AttributeSet attrs) {
super(context, attrs);
resetDensity(context);
}
/**
* dip/dp转像素
*
* @param dipValue dip或 dp大小
* @return 像素值
*/
public static int dip2px(float dipValue) {
return (int) (dipValue * sDensity + 0.5f);
}
/**
* 像素转dip/dp
*
* @param pxValue 像素大小
* @return dip值
*/
public static int px2dip(float pxValue) {
final float scale = sDensity;
return (int) (pxValue / scale + 0.5f);
}
/**
* sp转px
*
* @param spValue sp大小
* @return 像素值
*/
public static int sp2px(float spValue) {
final float scale = sDensity;
return (int) (scale * spValue);
}
/**
* px转sp
*
* @param pxValue 像素大小
* @return sp值
*/
public static int px2sp(float pxValue) {
final float scale = sDensity;
return (int) (pxValue / scale);
}
public synchronized static void resetDensity(Context context) {
if (context != null && null != context.getResources()) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
sDensity = metrics.density;
sFontDensity = metrics.scaledDensity;
sDensityDpi = metrics.densityDpi;
sScaleX = getScreenWidth(context)/sDefaultWidth;
sScaleY = getScreenHeight(context)/sDefaultHeight;
try {
final ViewConfiguration configuration = ViewConfiguration.get(context);
if (null != configuration) {
sTouchSlop = configuration.getScaledTouchSlop();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
/**
* 获取屏幕宽度
* @param context
* @return
*/
public static int getScreenWidth(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return metrics.widthPixels;
}
/**
* 获取屏幕高度
* @param context
* @return
*/
public static int getScreenHeight(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return metrics.heightPixels;
}
}
获取FloatView的工具类FloatViewControl.java:
public class FloatViewControl {
private static FloatViewControl sInstance;
private FloatViewControl(){
//构造方法私有化
}
public static synchronized FloatViewControl getInstance(){
if(sInstance == null)
sInstance = new FloatViewControl();
return sInstance;
}
private FloatView mFloatView;
public void startAnimation(Activity activity) {
if (mFloatView == null) {
mFloatView = new FloatView(activity);
mFloatView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mFloatView.attachActivity(activity);
mFloatView.start();
}
}
public void stopAnimation(Activity activity) {
if (mFloatView != null) {
mFloatView.stop();
mFloatView.disAttach(activity);
mFloatView = null;
}
}
}
主界面activity_main.xml:
本文的可运行项目地址:
https://github.com/buder-cp/base_component_learn/tree/master/FloatView