The Android Floating Window button enables clicking and displaying the and hidden multifunction list

  • 2021-09-20 21:36:35
  • OfStack

Preface

Recently, in a project, it is necessary to make the screen recording function. Originally, there was a screen recording/control button in the application. After thinking, I felt that this effect was not good, so I wanted to make a floating window that can be suspended, so that the screen recording function can be controlled no matter what interface the mobile phone is in.

Here, we will build a floating window on the desktop, using the MVVM mode of DataBinding, so we will not mention these aspects much.

FloatNormalView

This is an ordinary floating window. There is only one button in the floating window. Click the button to display more buttons.

The first is the page layout:


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data>
  <variable
   name="viewModel"
   type="com.example.zjt.floatrecorder.FloatNormalViewModel"/>
 </data>

 <LinearLayout
  android:layout_width="50dp"
  android:layout_height="50dp"
  android:gravity="center">

  <RelativeLayout
   android:id="@+id/root"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:orientation="vertical">
   <!--  Icon, click and pop up the back button  -->
   <ImageView
    android:id="@+id/float_id"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:background="@drawable/ic_launcher_background"
    android:onClick="@{viewModel::onControlClick}"/>
  </RelativeLayout>
 </LinearLayout>
</layout>

The following 1-step introduction to the creation of this floating window.

1 display of floating window


//  Create WindowManager Object 
private WindowManager windowManager;
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

//  Object for creating a floating window LayoutParams
 private void initLayoutParams() {
  try {
   DisplayMetrics metrics = new DisplayMetrics();
   windowManager.getDefaultDisplay().getMetrics(metrics);
   screenWidth = metrics.widthPixels;
   screenHeight = metrics.heightPixels;
   lp = new WindowManager.LayoutParams();
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
   } else {
    lp.type = WindowManager.LayoutParams.TYPE_TOAST;
   }
   lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
     WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
   lp.gravity = Gravity.START | Gravity.TOP;
   lp.x = screenWidth - view.getLayoutParams().width * 2;
   lp.y = 0;
   lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
   lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
   lp.format = PixelFormat.TRANSPARENT;
  } catch (Exception e) {
  }
 }

The above creates WindowManager that controls the display of the floating window and LayoutParams that controls the layout of the floating window, respectively
Then use the following code to show the floating window:


public void show() {
  if (!isShowing) {
   isShowing = true;
   windowManager.addView(this, lp);
  }
 }

It is also very simple to remove the floating window, as follows:


public void dismiss() {
  if (isShowing) {
   isShowing = false;
   windowManager.removeView(this);
  }
 }

2 Touch Events

Touch events can make the floating window move with fingers


//  Interface 
FloatLayoutBinding layoutBinding = DataBindingUtil.inflate(LayoutInflater.from(context),R.layout.float_layout,this,false);
FloatNormalViewModel floatNormalViewModel = new FloatNormalViewModel(context,layoutBinding,onClickCallback);
layoutBinding.setViewModel(floatNormalViewModel);
addView(layoutBinding.getRoot());
view = layoutBinding.root;
isShowControlView = layoutBinding.floatId;// This is the control button 

//  Controlled variables 
private float downX, downY;
private float moveX, moveY;

//  Touch event 
isShowControlView.setOnTouchListener(new OnTouchListener() {
  @Override
  public boolean onTouch(View view, MotionEvent motionEvent) {
   switch (motionEvent.getActionMasked()) {
    case MotionEvent.ACTION_DOWN:
     downX = motionEvent.getRawX();
     downY = motionEvent.getRawY();
     break;
    case MotionEvent.ACTION_MOVE:
     moveX = motionEvent.getRawX() - downX;
     moveY = motionEvent.getRawY() - downY;
     downX += moveX;
     downY += moveY;
     updateViewPosition();
     break;
    }
    return false;
 }
});
private void updateViewPosition() {
  lp.x += (int) (moveX);
  lp.y += (int) (moveY);
  windowManager.updateViewLayout(this, lp);
}

3 Click Events

Click event implements a callback function, because the logic of click event should not be completed here, but should be controlled by the main layout, so a click interface is defined.

The processing sequence of events here is as follows: After clicking the button, the button handles the clicked event through the callback function, and the callback function is provided by Activity, Fragment, Service, etc., which created this View, and then the event processing is handed over to the outside.


//  Clicked interface 
public interface OnClickCallback {
 public void onClick(View view);
}
//  Control button click event 
public void onControlClick(View view){
 if(onClickCallback != null)
  onClickCallback.onClick(view);
}

Multifunctional floating window

The multifunctional floating window is similar to the above, except that there are more click events.

And how to complete the switching between the two floating windows, we can use the OnClickCallback callback interface used before, show one and hide the other, and if the two floating windows use the same LayoutParams, we can make the two display in the same position.


private void init() {
  floatNormalView = new FloatNormalView(context, new OnClickCallback() {
   @Override
   public void onClick(View view) {
    floatControlView.setLayoutParams(floatNormalView.getLayoutParams());
    floatControlView.show();
    floatNormalView.dismiss();
   }
  });
  floatControlView = new FloatControlView(context, new OnClickCallback() {
   @Override
   public void onClick(View view) {
    floatNormalView.setLayoutParams(floatControlView.getLayoutParams());
    floatNormalView.show();
    floatControlView.dismiss();
   }
  }, new FloatControlViewModel.OnVisibleChangeListener() {
   @Override
   public void onChange(boolean isVisible) {
    if (isControlVisible) {
     floatControlView.show();
     floatNormalView.dismiss();
    } else {
     floatControlView.dismiss();
     floatNormalView.show();
    }
   }
  });
  floatNormalView.show();
 }

Related articles: