Effect of Android imitating suspension window of IOS system

  • 2021-12-21 04:51:52
  • OfStack

In some occasions, it will be very convenient for us to use the suspension window, such as the suspension window of IOS system, the suspension window of 360 or other mobile phone guards, etc.

In this blog, we create two floating windows, opening or closing the large floating window by clicking on the small floating window (1 playback controller).

The code is as follows:

Before that, we need to apply for permission in manifest:


<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

In addition, we need to manually find the application permission management in the mobile phone for the permission of floating window, and allow this permission to go

Interface code for small floating window float_normal_view. xml:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="65dp"
    android:layout_height="65dp"
    android:id="@+id/ll_float_normal"
    android:background="@drawable/float_bg"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_show_control_view"
        android:layout_gravity="center"
        android:background="@drawable/white_ring"
        android:layout_width="35dp"
        android:orientation="vertical"
        android:layout_height="35dp" >

    </ImageView>

</LinearLayout>

Interface code for large floating window float_control_view:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_float_control"
    android:layout_width="300dp"
    android:layout_height="100dp"
    android:background="@drawable/float_bg"
    android:gravity="center_horizontal|bottom"
    android:orientation="vertical">

    <SeekBar
        android:id="@+id/timeline"
        android:paddingTop="3dp"
        android:paddingBottom="3dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:focusable="true"
        android:maxHeight="5.0dip"
        android:minHeight="5.0dip"
        android:paddingLeft="16.0dip"
        android:paddingRight="16.0dip"
        android:progressDrawable="@drawable/po_seekbar"
        android:thumb="@drawable/seekbar_thumb" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:paddingBottom="10dp"
        android:paddingEnd="20dp"
        android:paddingStart="20dp"
        android:paddingTop="10dp">

        <ImageButton
            android:id="@+id/ibt_rewind"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_centerVertical="true"
            android:layout_marginEnd="20dp"
            android:layout_marginRight="20dp"
            android:layout_toLeftOf="@+id/ibt_play"
            android:layout_toStartOf="@+id/ibt_play"
            android:background="@drawable/rewind" />

        <ImageButton
            android:id="@+id/ibt_play"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_centerHorizontal="true"
            android:background="@drawable/pause" />

        <ImageButton
            android:id="@+id/ibt_forward"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20dp"
            android:layout_marginStart="20dp"
            android:layout_toEndOf="@+id/ibt_play"
            android:layout_toRightOf="@+id/ibt_play"
            android:background="@drawable/forward" />

    </RelativeLayout>


</LinearLayout>

Entry activity (FloatActivity):


public class FloatActivity extends Activity {

    MyWindowManager myWindowManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myWindowManager = MyWindowManager.getInstance();
        myWindowManager.createNormalView(this.getApplicationContext());
    }
}

Floating window manager MyWindowManager:


/**
 * Created by shiweixian on 2017/3/7.
 *  Floating window manager 
 *  Create, remove 
 *  Singleton pattern 
 */
public class MyWindowManager {

    private FloatNormalView normalView;
    private FloatControlView controlView;

    private static MyWindowManager instance;
    private WindowManager windowManager;

    private MyWindowManager() {
    }

    public static MyWindowManager getInstance() {
        if (instance == null)
            instance = new MyWindowManager();
        return instance;
    }

    private WindowManager getWindowManager(Context context) {
        if (windowManager == null)
            windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        return windowManager;
    }

    /**
     *  Judge whether a small floating window exists or not 
     *
     * @return
     */
    public boolean isNormalViewExists() {
        return normalView != null;
    }

    /**
     *  Judge whether the large floating window of the player exists or not 
     *
     * @return
     */
    public boolean isControlViewExists() {
        return controlView != null;
    }

    /**
     *  Create a small floating window 
     */
    public void createNormalView(Context context) {
        if (normalView == null) {
            normalView = new FloatNormalView(context);
        }
    }


    /**
     *  Remove floating window 
     *
     * @param context
     */
    public void removeNormalView(Context context) {
        if (normalView != null) {
            windowManager.removeView(normalView);
            normalView = null;
        }
    }

    /**
     *  Create a small floating window 
     */
    public void createControlView(Context context) {
        if (controlView == null)
            controlView = new FloatControlView(context);
    }

    /**
     *  Remove floating window 
     *
     * @param context
     */
    public void removeControlView(Context context) {
        if (controlView != null) {
            WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            windowManager.removeView(controlView);
            controlView = null;
        }
    }
}

Small suspension window FloatNormalView:


/**
 * Created by shiwe on 2017/3/7.
 *  Reduced floating window 
 */
public class FloatNormalView extends LinearLayout {

    /**
     *  Record the width of the small floating window 
     */
    public static int viewWidth;

    /**
     *  Record the height of the small floating window 
     */
    public static int viewHeight;

    /**
     *  Record the height of the system status bar 
     */
    private static int statusBarHeight;

    /**
     *  Used to update the position of the small floating window 
     */
    private WindowManager windowManager;

    /**
     *  Parameters of small floating window 
     */
    private WindowManager.LayoutParams mParams;

    /**
     *  Record the abscissa value of the current finger position on the screen 
     */
    private float xInScreen;

    /**
     *  Record the ordinate value of the current finger position on the screen 
     */
    private float yInScreen;

    /**
     *  Record the value of abscissa on the screen when the finger is pressed 
     */
    private float xDownInScreen;

    /**
     *  Record the value of the ordinate on the screen when the finger is pressed 
     */
    private float yDownInScreen;

    /**
     *  Record the value of the small floating window when the finger is pressed View The value of the abscissa on the 
     */
    private float xInView;

    /**
     *  Record the value of the small floating window when the finger is pressed View The value of the ordinate on the 
     */
    private float yInView;

    public FloatNormalView(Context context) {
        super(context);
        windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        LayoutInflater.from(context).inflate(R.layout.float_normal_view, this);
        View view = findViewById(R.id.ll_float_normal);
        viewWidth = view.getLayoutParams().width;
        viewHeight = view.getLayoutParams().height;
        initLayoutParams();
    }

    /**
     *  Initialization parameter 
     */
    private void initLayoutParams() {
        // Screen width and height 
        int screenWidth = windowManager.getDefaultDisplay().getWidth();
        int screenHeight = windowManager.getDefaultDisplay().getHeight();

        mParams = new WindowManager.LayoutParams();
        // Always appears above the application window. 
        mParams.type = WindowManager.LayoutParams.TYPE_PHONE;

        // FLAG_NOT_TOUCH_MODAL Do not block event delivery to subsequent windows 
        // FLAG_NOT_FOCUSABLE  When the floating window is small, the application icon behind it changes from non-long press to long press , Do not set this flag If, home There will be problems with the screen drawing of the page 
        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

        // Default display position of floating window 
        mParams.gravity = Gravity.START | Gravity.TOP;
        // Specify a location 
        mParams.x = screenWidth - viewWidth * 2;
        mParams.y = screenHeight / 2 + viewHeight * 2;
        // Width and height of floating window 
        mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        mParams.format = PixelFormat.TRANSPARENT;
        windowManager.addView(this, mParams);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //  Record the necessary data when the finger is pressed , The value of the ordinate needs to be subtracted from the height of the status bar 
                xInView = event.getX();
                yInView = event.getY();
                xDownInScreen = event.getRawX();
                yDownInScreen = event.getRawY() - getStatusBarHeight();
                xInScreen = event.getRawX();
                yInScreen = event.getRawY() - getStatusBarHeight();
                break;
            case MotionEvent.ACTION_MOVE:
                xInScreen = event.getRawX();
                yInScreen = event.getRawY() - getStatusBarHeight();
                //  Update the position of the small floating window when the finger moves 
                updateViewPosition();
                break;
            case MotionEvent.ACTION_UP:
                //  If your finger leaves the screen, xDownInScreen And xInScreen Equal, and yDownInScreen And yInScreen Is equal, the click event is considered to have been triggered. 
                if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {
                    openOrCloseControlView();
                }
                break;
            default:
                break;
        }
        return true;
    }

    /**
     *  Pass in the parameters of the small floating window to update the position of the small floating window. 
     *
     * @param params  Parameters of small floating window 
     */
    public void setParams(WindowManager.LayoutParams params) {
        mParams = params;
    }

    /**
     *  Updates the position of the small floating window in the screen. 
     */
    private void updateViewPosition() {
        mParams.x = (int) (xInScreen - xInView);
        mParams.y = (int) (yInScreen - yInView);
        windowManager.updateViewLayout(this, mParams);
    }

    /**
     *  Open or close the large floating window. 
     */
    private void openOrCloseControlView() {
        MyWindowManager manager = MyWindowManager.getInstance();
        if (!manager.isControlViewExists())
            manager.createControlView(getContext());
        else
            manager.removeControlView(getContext());
    }

    /**
     *  Used to get the height of the status bar. 
     *
     * @return  Returns the pixel value of the status bar height. 
     */
    private int getStatusBarHeight() {
        if (statusBarHeight == 0) {
            try {
                Class<?> c = Class.forName("com.android.internal.R$dimen");
                Object o = c.newInstance();
                Field field = c.getField("status_bar_height");
                int x = (Integer) field.get(o);
                statusBarHeight = getResources().getDimensionPixelSize(x);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return statusBarHeight;
    }
}

Large suspension window FloatControlView:


/**
 * Created by shiwe on 2017/3/7.
 *  Reduced floating window 
 */
public class FloatNormalView extends LinearLayout {

    /**
     *  Record the width of the small floating window 
     */
    public static int viewWidth;

    /**
     *  Record the height of the small floating window 
     */
    public static int viewHeight;

    /**
     *  Record the height of the system status bar 
     */
    private static int statusBarHeight;

    /**
     *  Used to update the position of the small floating window 
     */
    private WindowManager windowManager;

    /**
     *  Parameters of small floating window 
     */
    private WindowManager.LayoutParams mParams;

    /**
     *  Record the abscissa value of the current finger position on the screen 
     */
    private float xInScreen;

    /**
     *  Record the ordinate value of the current finger position on the screen 
     */
    private float yInScreen;

    /**
     *  Record the value of abscissa on the screen when the finger is pressed 
     */
    private float xDownInScreen;

    /**
     *  Record the value of the ordinate on the screen when the finger is pressed 
     */
    private float yDownInScreen;

    /**
     *  Record the value of the small floating window when the finger is pressed View The value of the abscissa on the 
     */
    private float xInView;

    /**
     *  Record the value of the small floating window when the finger is pressed View The value of the ordinate on the 
     */
    private float yInView;

    public FloatNormalView(Context context) {
        super(context);
        windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        LayoutInflater.from(context).inflate(R.layout.float_normal_view, this);
        View view = findViewById(R.id.ll_float_normal);
        viewWidth = view.getLayoutParams().width;
        viewHeight = view.getLayoutParams().height;
        initLayoutParams();
    }

    /**
     *  Initialization parameter 
     */
    private void initLayoutParams() {
        // Screen width and height 
        int screenWidth = windowManager.getDefaultDisplay().getWidth();
        int screenHeight = windowManager.getDefaultDisplay().getHeight();

        mParams = new WindowManager.LayoutParams();
        // Always appears above the application window. 
        mParams.type = WindowManager.LayoutParams.TYPE_PHONE;

        // FLAG_NOT_TOUCH_MODAL Do not block event delivery to subsequent windows 
        // FLAG_NOT_FOCUSABLE  When the floating window is small, the application icon behind it changes from non-long press to long press , Do not set this flag If, home There will be problems with the screen drawing of the page 
        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

        // Default display position of floating window 
        mParams.gravity = Gravity.START | Gravity.TOP;
        // Specify a location 
        mParams.x = screenWidth - viewWidth * 2;
        mParams.y = screenHeight / 2 + viewHeight * 2;
        // Width and height of floating window 
        mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        mParams.format = PixelFormat.TRANSPARENT;
        windowManager.addView(this, mParams);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //  Record the necessary data when the finger is pressed , The value of the ordinate needs to be subtracted from the height of the status bar 
                xInView = event.getX();
                yInView = event.getY();
                xDownInScreen = event.getRawX();
                yDownInScreen = event.getRawY() - getStatusBarHeight();
                xInScreen = event.getRawX();
                yInScreen = event.getRawY() - getStatusBarHeight();
                break;
            case MotionEvent.ACTION_MOVE:
                xInScreen = event.getRawX();
                yInScreen = event.getRawY() - getStatusBarHeight();
                //  Update the position of the small floating window when the finger moves 
                updateViewPosition();
                break;
            case MotionEvent.ACTION_UP:
                //  If your finger leaves the screen, xDownInScreen And xInScreen Equal, and yDownInScreen And yInScreen Is equal, the click event is considered to have been triggered. 
                if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {
                    openOrCloseControlView();
                }
                break;
            default:
                break;
        }
        return true;
    }

    /**
     *  Pass in the parameters of the small floating window to update the position of the small floating window. 
     *
     * @param params  Parameters of small floating window 
     */
    public void setParams(WindowManager.LayoutParams params) {
        mParams = params;
    }

    /**
     *  Updates the position of the small floating window in the screen. 
     */
    private void updateViewPosition() {
        mParams.x = (int) (xInScreen - xInView);
        mParams.y = (int) (yInScreen - yInView);
        windowManager.updateViewLayout(this, mParams);
    }

    /**
     *  Open or close the large floating window. 
     */
    private void openOrCloseControlView() {
        MyWindowManager manager = MyWindowManager.getInstance();
        if (!manager.isControlViewExists())
            manager.createControlView(getContext());
        else
            manager.removeControlView(getContext());
    }

    /**
     *  Used to get the height of the status bar. 
     *
     * @return  Returns the pixel value of the status bar height. 
     */
    private int getStatusBarHeight() {
        if (statusBarHeight == 0) {
            try {
                Class<?> c = Class.forName("com.android.internal.R$dimen");
                Object o = c.newInstance();
                Field field = c.getField("status_bar_height");
                int x = (Integer) field.get(o);
                statusBarHeight = getResources().getDimensionPixelSize(x);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return statusBarHeight;
    }
}

Related articles: