Android Floating View

Apr 26, 2017


本文

http://afra55.github.io/2017/04/26/floating_view/

图示

demo动画

前情提要

如上图所示,是一个悬浮窗,有移动动画,有大图隐藏小图显示的动画。 使用的是 WindowManager.addView 方法添加悬浮框。 建议有多个动画, 则 add 多个 view,不要放到一个里面。 此文也是在前人的基础上改编优化而来。 本文不会提供资源文件和demo。 只有代码及注释。

Code

有两个布局:一个 是显示大图的布局, 一个是现实小图及底部文字的布局。

大布局 layout_float_big_img

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.AppCompatImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/float_image"
    android:layout_width="150dp"
    android:layout_height="150dp"
    android:adjustViewBounds="true"
    android:tag="icon_right_float_kid"
    android:src="@drawable/icon_right_float_kid" />

小布局 layout_float_flower

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <FrameLayout
            android:id="@+id/float_image_container"
            android:layout_width="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_height="wrap_content">

            <!--<include layout="@layout/layout_float_big_img" />-->

            <android.support.v7.widget.AppCompatImageView
                android:id="@+id/float_small_image"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:translationY="50dp"
                android:layout_gravity="center_horizontal|bottom"
                android:adjustViewBounds="true"
                android:src="@drawable/icon_right_float_kid" />

        </FrameLayout>

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

            <TextView
                android:id="@+id/float_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:padding="5dp"
                android:text="@string/sticker"
                android:textColor="#FEA8B9"
                android:background="@drawable/bg_float_tip" />

        </FrameLayout>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="1dp"
            android:layout_gravity="center_horizontal"
            android:padding="5dp"
            android:text="@string/sticker"/>

    </LinearLayout>

</FrameLayout>

提供一个服务来启动 悬浮窗, 启动服务就可以显示悬浮窗

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.IBinder;
import android.view.WindowManager;

import java.util.Timer;
import java.util.TimerTask;

public class FloatViewManagerService extends Service {

    public static void start(Context context) {
        Intent intent = new Intent(context, FloatViewManagerService.class);
        context.startService(intent);
    }

    public static void stop(Context context) {
        Intent intent = new Intent(context, FloatViewManagerService.class);
        context.stopService(intent);
    }

    private int lastOrientation;

    public FloatViewManagerService() {
    }

    /**
     * 定时器,定时进行检测当前应该创建还是移除悬浮窗。
     */
    private Timer timer;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        WindowManager windowManager = (WindowManager) AppApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
        lastOrientation = windowManager.getDefaultDisplay().getRotation();

        // 开启定时器,每隔0.5秒刷新一次
        if (timer == null) {
            timer = new Timer();
            timer.scheduleAtFixedRate(new RefreshTask(), 0, 3000);
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Service被终止的同时也停止定时器继续运行
        FloatViewController.getInstance().hide();
        timer.cancel();
        timer = null;
    }

    private class RefreshTask extends TimerTask {

        @Override
        public void run() {
            // 处理显示或者移除悬浮框
            if (!FloatViewController.getInstance().isPauseToRemove() && FloatViewController.getInstance().isRemoved()) {
                FloatViewController.getInstance().show();
            }
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (lastOrientation != newConfig.orientation) {
            if (!FloatViewController.getInstance().isPauseToRemove()) {
                FloatViewController.getInstance().show();
            }
            lastOrientation = newConfig.orientation;
        }
    }
}

(重点)浮动窗口的控制类

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Property;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;


/**
 * Created by yangshuai on 2017/4/17.
 * 悬浮按钮控制类
 */
public class FloatViewController implements View.OnTouchListener {

    private static final String TAG = FloatViewController.class.getSimpleName();

    private static class SingletonHolder {
        @SuppressLint("StaticFieldLeak")
        private static FloatViewController instance = new FloatViewController();
    }

    private Context getContext() {
        return AppApplication.getInstance();
    }

    public static FloatViewController getInstance() {
        return SingletonHolder.instance;
    }


    private FloatViewController() {
        mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);

        isRemoved = true;

        getScreenSize();

        initView();
    }

    /**
     * Flag 移动到边缘
     */
    private static final int FLAG_MOVE_TO_EDGE = 10010;

    /**
     * Flag 在边缘隐藏大图,显示小图标
     */
    private static final int FLAG_HIDE_TO_EDGE = 10011;

    /**
     * Flag 在边缘显示大图标,隐藏小图标
     */
    private static final int FLAG_SHOW_TO_EDGE = 10012;

    /**
     * TAG 用于标志 大图显示的 靠近底部的图片
     */
    private static final String TAG_BOTTOM_ICON = "icon_float_bottom_kid";

    /**
     * TAG 用于标志 大图显示的 靠近左右的图片
     */
    private static final String TAG_RIGHT_ICON = "icon_right_float_kid";

    /**
     * 需要同步布局中的大小
     * 贴边显示时的 最小宽度
     */
    private static final int DEFAULT_HIDE_VIEW_SIZE = dp2px(50);

    /**
     * 需要同步布局中的大小
     * 正常显示大图时的大小
     */
    private static int DEFAULT_SHOW_SIZE = dp2px(150);

    /**
     * 需要同步布局中的大小
     * 显示贴边隐藏大图 动画 的延时
     */
    private final int SHOW_HIDE_VIEW_DELAYED_TIME = 5000;

    /**
     * 是否被移除
     */
    private boolean isRemoved = false;

    private WindowManager mWindowManager;

    /**
     * 大图和小图的 参数
     */
    private WindowManager.LayoutParams mSmallLayoutParams, mBigLayoutParams;

    /**
     * 屏幕宽高
     */
    private int mScreenWidth, mScreenHeight;

    /**
     * 布局对照
     *
     * @see #initView()
     */
    private ViewGroup mSmallLayoutContainer;
    private ViewGroup mFloatTextViewContainer;
    private ViewGroup mFloatSmallImageContainer;
    private ImageView mFloatBigImageView;
    private ImageView mFloatSmallImageView;
    private TextView mFloatTextView;

    /**
     * 透明度
     */
    private float mCurrentIconAlpha = 1f;

    /**
     * 是否显示 大图
     */
    private boolean isShowBigLayout;

    /**
     * 是否正在移动到边缘
     */
    private boolean isMovingToEdge;


    private float mTouchStartX;
    private float mTouchStartY;

    /**
     * 是否正在拖拽
     */
    private boolean isDragMoving;

    private static final int mScaledTouchSlop = 5;

    /**
     * 是否可拖拽
     */
    private static final boolean canDrag = true;

    /**
     * 移动动画
     */
    private ValueAnimator smallImgMoveToEdgeAnim;
    private ValueAnimator bigImgMoveToEdgeAnim;
    private ObjectAnimator translateToEdgeHide;
    private ObjectAnimator showSmallFloatImageAnim;
    private ObjectAnimator hideOffsetLeftOrRightAnim;
    private ObjectAnimator showOffsetLeftOrRightAnim;

    /**
     * 是否暂时移除 悬浮框
     */
    private boolean isPauseToRemove = false;

    private void initView() {

        if (mSmallLayoutContainer == null) {
            mSmallLayoutContainer = (ViewGroup) View.inflate(getContext(), R.layout.layout_float_flower, null);
        }
        if (mFloatBigImageView == null) {
            mFloatBigImageView = (ImageView) View.inflate(getContext(), R.layout.layout_float_big_img, null);
        }

        if (mSmallLayoutContainer != null && mFloatTextView == null) {
            mFloatTextView = ((TextView) mSmallLayoutContainer.findViewById(R.id.float_text));
        }

        if (mSmallLayoutContainer != null && mFloatTextViewContainer == null) {
            mFloatTextViewContainer = (ViewGroup) mSmallLayoutContainer.findViewById(R.id.float_text_container);
        }

        if (mSmallLayoutContainer != null && mFloatSmallImageContainer == null) {
            mFloatSmallImageContainer = (ViewGroup) mSmallLayoutContainer.findViewById(R.id.float_image_container);
        }

        if (mSmallLayoutContainer != null && mFloatSmallImageView == null) {
            mFloatSmallImageView = (ImageView) mSmallLayoutContainer.findViewById(R.id.float_small_image);
        }

        // event listeners
        addFloatViewTouchListener();
    }

    /**
     * 是否有动画运行种
     *
     * @return true 有 ; false 没有。
     */
    private boolean isAnimRunning() {
        return (translateToEdgeHide != null && translateToEdgeHide.isRunning())
                || (smallImgMoveToEdgeAnim != null && smallImgMoveToEdgeAnim.isRunning())
                || (bigImgMoveToEdgeAnim != null && bigImgMoveToEdgeAnim.isRunning())
                || (hideOffsetLeftOrRightAnim != null && hideOffsetLeftOrRightAnim.isRunning())
                || (showOffsetLeftOrRightAnim != null && showOffsetLeftOrRightAnim.isRunning())
                ;
    }


    /**
     * handler 用于处理各种 布局更换
     */
    private Handler mMainHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            synchronized (FloatViewController.this) {
                switch (msg.what) {
                    case FLAG_MOVE_TO_EDGE:
                        // 移动到边缘
                        int desX = (int) msg.obj;
                        moveSmallImageToEdge(desX);
                        moveBigImageToEdge(desX);
                        break;
                    case FLAG_HIDE_TO_EDGE:
                        // 隐藏大布局,显示小布局
                        if (isAnimRunning()) break;

                        // 判断是在左边缘还是在右边缘
                        int translateToHideLength = (Math.abs(mBigLayoutParams.x) < Math.abs(mBigLayoutParams.x - mScreenWidth))
                                ? -mFloatBigImageView.getWidth() : mFloatBigImageView.getWidth();

                        Property<View, Float> hideProperty = View.TRANSLATION_X;
                        if (isAlignBottom()) {
                            // 如果在底部,就是 y 轴的移动动画
                            hideProperty = View.TRANSLATION_Y;
                            translateToHideLength *= -1;
                        }
                        startTranslateHideShowAnim(
                                translateToHideLength
                                , true, hideProperty);

                        break;

                    case FLAG_SHOW_TO_EDGE:

                        if (isAnimRunning()) break;

                        Property<View, Float> showProperty = View.TRANSLATION_X;

                        if (isAlignBottom()) {
                            showProperty = View.TRANSLATION_Y;
                        }

                        startTranslateHideShowAnim(
                                0
                                , false, showProperty);


                        break;
                }
            }
        }
    };

    /**
     * 移动小布局到边缘
     *
     * @param desX desX
     */
    private void moveSmallImageToEdge(int desX) {
        if (smallImgMoveToEdgeAnim != null && smallImgMoveToEdgeAnim.isRunning()) {
            smallImgMoveToEdgeAnim.cancel();
        }
        smallImgMoveToEdgeAnim = ValueAnimator.ofInt(mSmallLayoutParams.x, desX);
        smallImgMoveToEdgeAnim.setDuration(300);
        smallImgMoveToEdgeAnim.setInterpolator(new AccelerateDecelerateInterpolator());
        smallImgMoveToEdgeAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mSmallLayoutParams.x = (int) animation.getAnimatedValue();
                try {
                    mWindowManager.updateViewLayout(mSmallLayoutContainer, mSmallLayoutParams);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        smallImgMoveToEdgeAnim.start();
    }

    /**
     * 移动大布局到边缘, 其实可以复用
     *
     * @param desX des
     * @see #moveSmallImageToEdge(int)
     */
    private void moveBigImageToEdge(int desX) {
        if (bigImgMoveToEdgeAnim != null && bigImgMoveToEdgeAnim.isRunning()) {
            bigImgMoveToEdgeAnim.cancel();
        }
        bigImgMoveToEdgeAnim = ValueAnimator.ofInt(mBigLayoutParams.x, desX);
        bigImgMoveToEdgeAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mBigLayoutParams.x = (int) animation.getAnimatedValue();
                try {
                    mWindowManager.updateViewLayout(mFloatBigImageView, mBigLayoutParams);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (animation.getAnimatedFraction() >= 1) {
                    isMovingToEdge = false;
                    mMainHandler.removeMessages(FLAG_HIDE_TO_EDGE);
                    mMainHandler.sendEmptyMessageDelayed(FLAG_HIDE_TO_EDGE, SHOW_HIDE_VIEW_DELAYED_TIME);

                    startEdgeOffsetAnim();
                }
            }
        });
        bigImgMoveToEdgeAnim.setDuration(300);
        bigImgMoveToEdgeAnim.setInterpolator(new AccelerateDecelerateInterpolator());
        bigImgMoveToEdgeAnim.start();
    }

    /**
     * 在做边缘或者右边缘的时候,还要右 50 dp 的移动
     */
    private void startEdgeOffsetAnim() {
        hideOffsetLeftOrRightAnim = ObjectAnimator.ofFloat(
                mFloatBigImageView
                , View.X
                , (Math.abs(mSmallLayoutParams.x) < Math.abs(mSmallLayoutParams.x - mScreenWidth))
                        ? -dp2px(50) : dp2px(50));
        hideOffsetLeftOrRightAnim.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mMainHandler.removeMessages(FLAG_HIDE_TO_EDGE);
                mMainHandler.sendEmptyMessageDelayed(FLAG_HIDE_TO_EDGE, SHOW_HIDE_VIEW_DELAYED_TIME);
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        hideOffsetLeftOrRightAnim.start();
    }


    /**
     * 显示或隐藏大图标动画
     *
     * @param translateToHideLength 移动长度
     * @param isShowHideView        是否显示小图标
     * @param property              移动的属性
     */
    private void startTranslateHideShowAnim(int translateToHideLength, final boolean isShowHideView, final Property<View, Float> property) {
        translateToEdgeHide = ObjectAnimator.ofFloat(mFloatBigImageView, property, translateToHideLength);
        long delayTime = 100;
        translateToEdgeHide.setDuration(delayTime);
        if (isShowHideView) {
            mFloatTextView.setText(getContext().getString(R.string.sticker));
        } else {
            mFloatTextView.setText("收起");
        }
        long showSmallImgDelayed = delayTime / 3;
        if (!isShowHideView) {
            showSmallImgDelayed = 0;
        }

        // 在隐藏 大图的同时,显示小图
        mMainHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (showSmallFloatImageAnim != null && showSmallFloatImageAnim.isRunning()) {
                    return;
                }

                showSmallFloatImageAnim(isShowHideView);
            }
        }, showSmallImgDelayed);

        translateToEdgeHide.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                mFloatBigImageView.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationEnd(Animator animation) {

                if (!isShowHideView) {
                    if (property == View.TRANSLATION_X) {
                        startEdgeOffsetAnim();
                    } else if (property == View.TRANSLATION_Y) {
                        mMainHandler.removeMessages(FLAG_HIDE_TO_EDGE);
                        mMainHandler.sendEmptyMessageDelayed(FLAG_HIDE_TO_EDGE, SHOW_HIDE_VIEW_DELAYED_TIME);
                    }
                } else {
                    mFloatBigImageView.setVisibility(View.GONE);
                }

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        translateToEdgeHide.start();
    }

    /**
     * 显示小图动画
     *
     * @param isShowHideView 是否显示小图
     */
    private void showSmallFloatImageAnim(final boolean isShowHideView) {

        mFloatBigImageView.requestLayout();

        showSmallFloatImageAnim = ObjectAnimator.ofFloat(mFloatSmallImageView, View.TRANSLATION_Y
                , isShowHideView ? 0 : dp2px(50));
        showSmallFloatImageAnim.setDuration(100);
        showSmallFloatImageAnim.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                isShowBigLayout = !isShowHideView;
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        showSmallFloatImageAnim
                .start();
    }


    @SuppressLint("ObsoleteSdkInt")
    private void getScreenSize() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            Point point = new Point();
            mWindowManager.getDefaultDisplay().getSize(point);
            mScreenWidth = point.x;
            mScreenHeight = point.y;
        } else {
            mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
            mScreenHeight = mWindowManager.getDefaultDisplay().getHeight();
        }
        mCurrentIconAlpha = 70 / 100f;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        if (isAnimRunning()) {
            return false;
        }

        if (isMovingToEdge) {
            return true;
        }

        removeHandler();

        float x = event.getRawX();
        float y = event.getRawY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                mTouchStartX = x;
                mTouchStartY = y;
                isDragMoving = false;
                break;
            case MotionEvent.ACTION_MOVE:

                if (showOffsetLeftOrRightAnim != null && showOffsetLeftOrRightAnim.isRunning()) {
                    return false;
                }

                if (mFloatBigImageView.getTranslationY() != 0) {
                    mFloatBigImageView.setTranslationY(0);
                    return false;
                }

                if (mFloatBigImageView.getTranslationX() != 0) {

                    showOffsetLeftOrRightAnim = ObjectAnimator.ofFloat(mFloatBigImageView, "translationX", 0);
                    showOffsetLeftOrRightAnim.setDuration(10);
                    showOffsetLeftOrRightAnim.start();

                    return false;
                }

                if (canDrag) {
                    if (isDragMoving || Math.abs(x - mTouchStartX) > mScaledTouchSlop || Math.abs(y - mTouchStartY) > mScaledTouchSlop) {
                        isDragMoving = true;
                    }

                    updateViewPosition(x, y);
                }
                break;
            case MotionEvent.ACTION_UP:
                if (!isDragMoving
                        && Math.abs(x - mTouchStartX) < mScaledTouchSlop
                        && Math.abs(y - mTouchStartY) < mScaledTouchSlop
                        ) {
                    
                    if (!isShowBigLayout) {
                        mMainHandler.sendEmptyMessage(FLAG_SHOW_TO_EDGE);
                        return false;
                    }
                    // 处理点击事件
                    //...........
                }

                if (canDrag) {
                    updateViewPosition(x, y - mSmallLayoutContainer.getHeight());
                }

                mTouchStartX = mTouchStartY = 0;

                moveToEdge();

            case MotionEvent.ACTION_OUTSIDE:
            case MotionEvent.ACTION_CANCEL:
                moveToEdge();
                break;
        }
        return true;
    }

    /**
     * 移动到边缘
     */
    private void moveToEdge() {
        mMainHandler.post(new Runnable() {
            @SuppressLint("ObsoleteSdkInt")
            @Override
            public void run() {

                if (isAlignBottom()) {
                    mMainHandler.removeMessages(FLAG_HIDE_TO_EDGE);
                    mMainHandler.sendEmptyMessageDelayed(FLAG_HIDE_TO_EDGE, SHOW_HIDE_VIEW_DELAYED_TIME);
                    return;
                }

                isMovingToEdge = true;
                initScreenData();
                int desBigX = 0;
                if (mBigLayoutParams.x > mScreenWidth / 2) {
                    desBigX = mScreenWidth;
                }
                mMainHandler.sendMessage(mMainHandler.obtainMessage(FLAG_MOVE_TO_EDGE, desBigX));
            }
        });
    }

    /**
     * 判断是否在底部
     *
     * @return true 是
     */
    private boolean isAlignBottom() {
        if (mBigLayoutParams.y + mFloatBigImageView.getHeight() >= mScreenHeight) {
            return true;
        }
        return false;
    }

    /**
     * 更新 视图的 位置
     *
     * @param x x
     * @param y y
     */
    private synchronized void updateViewPosition(float x, float y) {

        mSmallLayoutParams.x = (int) (x - mSmallLayoutContainer.getWidth() / 2);
        mBigLayoutParams.x = (int) (x - mFloatBigImageView.getWidth() / 2);

        if (mFloatBigImageView.getVisibility() == View.GONE) {
            mSmallLayoutParams.y = (int) (y - mFloatSmallImageView.getHeight() / 2);
            mBigLayoutParams.y = (int) (y - mFloatBigImageView.getHeight() + mFloatSmallImageView.getHeight() / 2);
        } else {
            mSmallLayoutParams.y = (int) (y + mFloatBigImageView.getHeight() / 2 - mFloatSmallImageView.getHeight());
            mBigLayoutParams.y = (int) (y - mFloatBigImageView.getHeight() / 2);
        }


        if (mSmallLayoutParams.x < 0) {
            mSmallLayoutParams.x = 0;
        }
        if (mSmallLayoutParams.y < 0) {
            mSmallLayoutParams.y = 0;
        }

        if (mBigLayoutParams.x < 0) {
            mBigLayoutParams.x = 0;
        }
        if (mBigLayoutParams.y < 0) {
            mBigLayoutParams.y = 0;
        }

        LogUtils.i(TAG, mBigLayoutParams.y + " | " + mScreenHeight);

        Object floatImageViewTag = mFloatBigImageView.getTag();
        if (mBigLayoutParams.y >= mScreenHeight - DEFAULT_SHOW_SIZE) {
            if (floatImageViewTag == null || !floatImageViewTag.equals(TAG_BOTTOM_ICON)) {
                mFloatBigImageView.setImageResource(R.drawable.icon_float_bottom_kid);
                mFloatBigImageView.setTag(TAG_BOTTOM_ICON);
            }
        } else {
            if (floatImageViewTag == null || !floatImageViewTag.equals(TAG_RIGHT_ICON)) {
                mFloatBigImageView.setImageResource(R.drawable.icon_right_float_kid);
                mFloatBigImageView.setTag(TAG_RIGHT_ICON);
            }
        }


        try {
            mWindowManager.updateViewLayout(mSmallLayoutContainer, mSmallLayoutParams);
            mWindowManager.updateViewLayout(mFloatBigImageView, mBigLayoutParams);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private void addFloatViewTouchListener() {
        if (mFloatBigImageView != null) {
            mFloatBigImageView.setOnTouchListener(this);
        }

        if (mFloatSmallImageView != null) {
            mFloatSmallImageView.setOnTouchListener(this);
        }

        if (mFloatSmallImageContainer != null) {
            mFloatSmallImageContainer.setOnTouchListener(this);
        }

        if (mFloatTextViewContainer != null) {
            mFloatTextViewContainer.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (isShowBigLayout) {
                        mMainHandler.sendEmptyMessage(FLAG_HIDE_TO_EDGE);
                    } else {
                        mMainHandler.sendEmptyMessage(FLAG_SHOW_TO_EDGE);
//                        showFloatDefaultView();
                    }
                }
            });
        }
    }

    private void removeFloatViewTouchListener() {
        if (mFloatBigImageView != null) {
            mFloatBigImageView.setOnTouchListener(null);
        }

        if (mFloatTextViewContainer != null) {
            mFloatTextViewContainer.setOnClickListener(null);
        }

        if (mFloatSmallImageContainer != null) {
            mFloatSmallImageContainer.setOnClickListener(null);
        }

        if (translateToEdgeHide != null && translateToEdgeHide.isRunning()) {
            translateToEdgeHide.cancel();
        }

        if (smallImgMoveToEdgeAnim != null && smallImgMoveToEdgeAnim.isRunning()) {
            smallImgMoveToEdgeAnim.cancel();
        }

        removeHandler();
    }

    private void removeHandler() {
        mMainHandler.removeMessages(FLAG_MOVE_TO_EDGE);
        mMainHandler.removeMessages(FLAG_HIDE_TO_EDGE);
        mMainHandler.removeMessages(FLAG_SHOW_TO_EDGE);
    }

    public synchronized void show() {
        if (isRemoved) {
            showFloatDefaultView();
            isRemoved = false;
        } else {
            addFloatViewTouchListener();
        }
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                synchronized (FloatViewController.this) {
                    if (mSmallLayoutContainer != null) {
                        mSmallLayoutContainer.setVisibility(View.VISIBLE);
                        moveToEdge();
                    }
                }
            }
        });

    }

    private void showFloatDefaultView() {
        if (mSmallLayoutParams == null || mBigLayoutParams == null) {
            reuseSavedWindowMangerPosition();
        }
        showFloatIcon();
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                synchronized (FloatViewController.this) {
                    int size;
                    size = ViewGroup.LayoutParams.WRAP_CONTENT;
                    reuseSavedWindowMangerPositionForSmall(size, size);
                    removeAllView();
                    try {
                        mSmallLayoutContainer.setAlpha(mCurrentIconAlpha);
                        mSmallLayoutContainer.setScaleX(1);
                        mSmallLayoutContainer.setScaleY(1);

                        mSmallLayoutContainer.setVisibility(View.VISIBLE);
                        mWindowManager.addView(mFloatBigImageView, mBigLayoutParams);
                        mWindowManager.addView(mSmallLayoutContainer, mSmallLayoutParams);

                        isShowBigLayout = true;
                    } catch (Throwable e) {
                        e.printStackTrace();
                        Toast.makeText(getContext(), "悬浮按钮开启失败,请手动开启!", Toast.LENGTH_LONG).show();
                        try {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(getContext())) {
                                // 悬浮开启判断
                                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                                        Uri.parse("package:" + getContext().getPackageName()));
                                getContext().startActivity(intent);
                                isRemoved = true;
                            }
                        } catch (Exception e1) {
                            e1.printStackTrace();
                        }
                    }

                    addFloatViewTouchListener();

                    moveToEdge();
                }
            }
        });
    }

    public void hide() {
        isRemoved = true;
        removeAllView();
    }

    private void removeAllView() {
        if (mWindowManager == null)
            mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        try {
            mWindowManager.removeView(mSmallLayoutContainer);
            mWindowManager.removeView(mFloatBigImageView);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (mSmallLayoutContainer != null) {
            mSmallLayoutContainer.setVisibility(View.INVISIBLE);
        }

        removeFloatViewTouchListener();

    }

    /**
     * 是否从屏幕上移除
     *
     * @return boolean
     */
    public boolean isRemoved() {
        return isRemoved;
    }

    private void showFloatIcon() {
        mMainHandler.post(new Runnable() {
            @Override
            public void run() {
                mMainHandler.removeMessages(FLAG_HIDE_TO_EDGE);
                mFloatBigImageView.setImageResource(R.drawable.icon_right_float_kid);

                mFloatBigImageView.requestLayout();
                mFloatTextView.setText("收起");
                mFloatBigImageView.setContentDescription("浮动视图");

                mFloatSmallImageView.setTranslationY(dp2px(50));
                mFloatBigImageView.setTranslationX(0);
                mFloatBigImageView.setTranslationY(0);
                reuseSavedWindowMangerPosition();

                try {
                    mWindowManager.updateViewLayout(mFloatBigImageView, mBigLayoutParams);
                    mWindowManager.updateViewLayout(mSmallLayoutContainer, mSmallLayoutParams);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                mMainHandler.sendEmptyMessageDelayed(FLAG_HIDE_TO_EDGE, SHOW_HIDE_VIEW_DELAYED_TIME);
            }
        });

    }

    private void reuseSavedWindowMangerPosition() {
        reuseSavedWindowMangerPositionForBig(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        reuseSavedWindowMangerPositionForSmall(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    }

    @SuppressLint("ObsoleteSdkInt")
    private void reuseSavedWindowMangerPositionForSmall(int width_vale, int height_value) {
        //获取windowManager
        if (mSmallLayoutParams == null) {
            DisplayMetrics displayMetrics = new DisplayMetrics();
            mWindowManager.getDefaultDisplay().getMetrics(displayMetrics);

            int flags = getFloatWindowFlags();
            int type = getFloatWindowType();
            initScreenData();
            int x = mScreenWidth;
            int y = mScreenHeight / 3 * 2 + DEFAULT_SHOW_SIZE / 2 - DEFAULT_HIDE_VIEW_SIZE;

            mSmallLayoutParams = new WindowManager.LayoutParams(width_vale, height_value, type, flags, PixelFormat.TRANSLUCENT);
            mSmallLayoutParams.gravity = Gravity.TOP | Gravity.START;
            mSmallLayoutParams.x = x;
            mSmallLayoutParams.y = y;
        } else {
            mSmallLayoutParams.width = width_vale;
            mSmallLayoutParams.height = height_value;
        }

    }

    private int getFloatWindowType() {
        int type;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(getContext())) {
            type = WindowManager.LayoutParams.TYPE_PHONE;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            type = WindowManager.LayoutParams.TYPE_TOAST;
        } else {
            type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        return type;
    }

    @SuppressLint("ObsoleteSdkInt")
    private void reuseSavedWindowMangerPositionForBig(int width_vale, int height_value) {
        //获取windowManager
        if (mBigLayoutParams == null) {

            int flags = getFloatWindowFlags();
            int type = getFloatWindowType();

            initScreenData();
            int x = mScreenWidth;
            int y = mScreenHeight / 3 * 2 - DEFAULT_SHOW_SIZE / 2;

            mBigLayoutParams = new WindowManager.LayoutParams(width_vale, height_value, type, flags, PixelFormat.TRANSLUCENT);
            mBigLayoutParams.gravity = Gravity.TOP | Gravity.START;
            mBigLayoutParams.x = x;
            mBigLayoutParams.y = y;
        } else {
            mBigLayoutParams.width = width_vale;
            mBigLayoutParams.height = height_value;
        }

    }

    private void initScreenData() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            Point point = new Point();
            mWindowManager.getDefaultDisplay().getSize(point);
            mScreenWidth = point.x;
            mScreenHeight = point.y;
        } else {
            mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
            mScreenHeight = mWindowManager.getDefaultDisplay().getHeight();
        }
    }

    private int getFloatWindowFlags() {
        return WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
    }

    private static int dp2px(float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, AppApplication.getInstance().getResources().getDisplayMetrics());
    }


    public boolean isPauseToRemove() {
        return isPauseToRemove;
    }

    // 暂时隐藏不显示
    public void setPauseToRemove(boolean pauseToRemove) {
        isPauseToRemove = pauseToRemove;
        if (!pauseToRemove) {
            show();
        } else {
            hide();
        }
    }
}

轮子已经制造,该怎么去转动呢?