Android project essential (forty-four) -->Android implements floating window

foreword

Floating windows are a relatively common requirement. For example, the video call interface is reduced into a floating window, and then users can handle things on other interfaces.

This article will explain the floating window implementation steps, principles, example codes, etc.

Realization principle

1. WindowManager interface

The interface drawing of Android is realized through the service WindowManangerof . So, since we want to implement a floating window that can be on an interface other than our own application, we need to use WindowManagerto achieve it.

(frameworks/base/core/java/android/view/WindowMananger.java)

@SystemService(Context.WINDOW_SERVICE)
public interface WindowManager extends ViewManager {
    
    
	...
}

WindowManagerIt implements ViewManagerthe interface and can WINDOW_SERVICEbe obtained by obtaining the system service. ViewManagerThe interface has addViewa method , and we use this method to add the floating window control to the screen.

2. LayoutParam setting

What needs to be emphasized here LayoutParamis typethe variable in . This variable is used to specify the window type.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
	layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    
    
    layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}

Implementation

Implement a floating window for automatic carousel.

1. Rendering

insert image description here

2. Declaration and application authority

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
@RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
    
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
    
    
            if (!Settings.canDrawOverlays(this)) {
    
    
                Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show();
            } else {
    
    
                Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
                startService(new Intent(MainActivity.this, FloatingImageDisplayService.class));
            }
        } 
    }
    
    public void startFloatingImageDisplayService(View view) {
    
    
        if (FloatingImageDisplayService.isStarted) {
    
    
            return;
        }
        if (!Settings.canDrawOverlays(this)) {
    
    
            Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
            startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 1);
        } else {
    
    
            startService(new Intent(MainActivity.this, FloatingImageDisplayService.class));
        }
    }
}

3. Build the controls needed for the floating window

image_display.xml

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

    <ImageView
        android:id="@+id/image_display_imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

4. Add the control to theWindowManager

@RequiresApi(api = Build.VERSION_CODES.M)
public class FloatingImageDisplayService extends Service {
    
    
    public static boolean isStarted = false;

    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;

    private View displayView;

    private int[] images;
    private int imageIndex = 0;

    private Handler changeImageHandler;

    @Override
    public void onCreate() {
    
    
        super.onCreate();
        isStarted = true;
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        layoutParams = new WindowManager.LayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
    
    
            layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        layoutParams.format = PixelFormat.RGBA_8888;
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        layoutParams.width = 500;
        layoutParams.height = 500;
        layoutParams.x = 300;
        layoutParams.y = 300;

        images = new int[] {
    
    
                R.mipmap.image_01,
                R.mipmap.image_02,
                R.mipmap.image_03,
                R.mipmap.image_04,
                R.mipmap.image_05
        };

        changeImageHandler = new Handler(this.getMainLooper(), changeImageCallback);
    }



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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    
    
        showFloatingWindow();
        return super.onStartCommand(intent, flags, startId);
    }


    private void showFloatingWindow() {
    
    
        if (Settings.canDrawOverlays(this)) {
    
    
            LayoutInflater layoutInflater = LayoutInflater.from(this);
            displayView = layoutInflater.inflate(R.layout.image_display, null);
            displayView.setOnTouchListener(new FloatingOnTouchListener());
            ImageView imageView = displayView.findViewById(R.id.image_display_imageview);
            imageView.setImageResource(images[imageIndex]);
            windowManager.addView(displayView, layoutParams);

            changeImageHandler.sendEmptyMessageDelayed(0, 2000);
        }
    }

    private Handler.Callback changeImageCallback = new Handler.Callback() {
    
    
        @Override
        public boolean handleMessage(Message msg) {
    
    
            if (msg.what == 0) {
    
    
                imageIndex++;
                if (imageIndex >= 5) {
    
    
                    imageIndex = 0;
                }
                if (displayView != null) {
    
    
                    ((ImageView) displayView.findViewById(R.id.image_display_imageview)).setImageResource(images[imageIndex]);
                }

                changeImageHandler.sendEmptyMessageDelayed(0, 2000);
            }
            return false;
        }
    };

    private class FloatingOnTouchListener implements View.OnTouchListener {
    
    
        private int x;
        private int y;

        @Override
        public boolean onTouch(View view, MotionEvent event) {
    
    
            switch (event.getAction()) {
    
    
                case MotionEvent.ACTION_DOWN:
                    x = (int) event.getRawX();
                    y = (int) event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int nowX = (int) event.getRawX();
                    int nowY = (int) event.getRawY();
                    int movedX = nowX - x;
                    int movedY = nowY - y;
                    x = nowX;
                    y = nowY;
                    layoutParams.x = layoutParams.x + movedX;
                    layoutParams.y = layoutParams.y + movedY;
                    windowManager.updateViewLayout(view, layoutParams);
                    break;
                default:
                    break;
            }
            return false;
        }
    }
}

Guess you like

Origin blog.csdn.net/duoduo_11011/article/details/130031272