Android Overlay a View Ontop of Everything

Android overlay a view ontop of everything?

Simply use RelativeLayout or FrameLayout. The last child view will overlay everything else.

Android supports a pattern which Cocoa Touch SDK doesn't: Layout management.

Layout for iPhone means to position everything absolute (besides some strech factors). Layout in android means that children will be placed in relation to eachother.

Example (second EditText will completely cover the first one):

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/root_view">

<EditText
android:layout_width="fill_parent"
android:id="@+id/editText1"
android:layout_height="fill_parent">
</EditText>

<EditText
android:layout_width="fill_parent"
android:id="@+id/editText2"
android:layout_height="fill_parent">
<requestFocus></requestFocus>
</EditText>

</FrameLayout>

FrameLayout is some kind of view stack. Made for special cases.

RelativeLayout is pretty powerful. You can define rules like View A has to align parent layout bottom, View B has to align A bottom to top, etc

Update based on comment

Usually you set the content with setContentView(R.layout.your_layout) in onCreate (it will inflate the layout for you). You can do that manually and call setContentView(inflatedView), there's no difference.

The view itself might be a single view (like TextView) or a complex layout hierarchy (nested layouts, since all layouts are views themselves).

After calling setContentView your activity knows what its content looks like and you can use (FrameLayout) findViewById(R.id.root_view) to retrieve any view int this hierarchy (General pattern (ClassOfTheViewWithThisId) findViewById(R.id.declared_id_of_view)).

How to create an 'Always on top overlay' in Android

Alright. Heres a piece of code which does the job: (You can change the ImageView to any other thing and use it as an overlay.)

startPowerOverlay() function:

@SuppressLint("ClickableViewAccessibility")
private void startPowerOverlay(){
// Starts the button overlay.
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
overlayPowerBtn = new ImageView(this);
overlayPowerBtn.setImageResource(R.drawable.REPLACE_ME);

int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// APPLICATION_OVERLAY FOR ANDROID 26+ AS THE PREVIOUS VERSION RAISES ERRORS
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
// FOR PREVIOUS VERSIONS USE TYPE_PHONE AS THE NEW VERSION IS NOT SUPPORTED
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);

params.gravity = Gravity.TOP | Gravity.START;
params.x = 0;
params.y = 100;
params.height = 110;
params.width = 110;

windowManager.addView(overlayPowerBtn, params);

overlayPowerBtn.setOnTouchListener(new View.OnTouchListener() {
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
private long latestPressTime = 0;

@Override public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Save current x/y
initialX = params.x;
initialY = params.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
// Check for double clicks.
if (latestPressTime == 0 || latestPressTime + 500 < System.currentTimeMillis()) {
latestPressTime = System.currentTimeMillis();
} else {
// Doubleclicked. Do any action you'd like
}
return true;
case MotionEvent.ACTION_UP:
return true;
case MotionEvent.ACTION_MOVE:
params.x = initialX + (int) (event.getRawX() - initialTouchX);
params.y = initialY + (int) (event.getRawY() - initialTouchY);
windowManager.updateViewLayout(overlayPowerBtn, params);
return true;
}
return false;
}
});
}

on onCreate():

        // Check for overlay permission. If not enabled, request for it. If enabled, show the overlay
if(Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)){
CharSequence text = "Please grant the access to the application.";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.fromParts("package", getPackageName(), null)));
} else {
startPowerOverlay();
}

on onDestroy():

        if (overlayPowerBtn != null)
windowManager.removeView(overlayPowerBtn);

Hope it helps.

How to create Overlay layout in android

Use RelativeLayout or FrameLayout. The last child view will overlay everything else.

To be sure the overlay view is on top, you can call ViewGroup.bringChildViewToFront() on the relative layout.

Example:

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/root_view">

<EditText
android:layout_width="fill_parent"
android:id="@+id/editText1"
android:layout_height="fill_parent">
</EditText>

<EditText
android:layout_width="fill_parent"
android:id="@+id/editText2"
android:layout_height="fill_parent">
<requestFocus></requestFocus>
</EditText>

</FrameLayout>

In this layout, editText2 will cover the editText1

How would I display one view as an overlay of another?

Use a RelativeLayout for starters.

You could use the ViewGroup.addView(View child, int index, ViewGroup.LayoutParams params) or a variant along with ViewGroup.removeView(View view) or ViewGroup.removeViewAt(int index).

This would obviously require you to inflate the views manually using LayoutInflater but you could keep a global reference to each after inflating and just flip between the two.

Android ConstraintLayout - Put one view on top of another view

Set an elevation on the ProgressBar; 2dp seems to work.

android:elevation="2dp"

You could also try setting translationZ as suggested in the accepted answer to a similar question.

I also came across this answer as an alternative.

Creating a system overlay window (always on top)

This might be a stupid solution. But it works. If you can improve it, please let me know.

OnCreate of your Service: I have used WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH flag. This is the only change in service.

@Override
public void onCreate() {
super.onCreate();
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
mView = new HUDView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
}

Now, you will start getting each and every click event. So, you need to rectify in your event handler.

In your ViewGroup touch event

@Override
public boolean onTouchEvent(MotionEvent event) {

// ATTENTION: GET THE X,Y OF EVENT FROM THE PARAMETER
// THEN CHECK IF THAT IS INSIDE YOUR DESIRED AREA

Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
return true;
}

Also you may need to add this permission to your manifest:

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

Add a view on top of all the Activities

In order to manage the show/view of the view I've used the solution proposed by Gopal.
I've attached onStop and onResume events so that the view is hidden when exiting application.

For the click events, I've realized that the type toast does not respond to click events. Therefore I've changed the type

params.type = WindowManager.LayoutParams.TYPE_TOAST;

to

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;

I've to add the following permision too:

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


Related Topics



Leave a reply



Submit