I'm trying to program an app that will use the edge lighting notification as shown in the picture. However, I have no idea what to use to handle that.
I have tried using canvas but that's not what I want since its limited to the app itself.
For a solution that completely covers the screen regardless of the state/size of the app, you have several options. Here are two effective methods:
This method involves creating a second activity that displays a transparent gradient border.
Pros:
Cons:
Create a custom theme in res/values/styles.xml
that makes the activity full-screen and transparent.
res/values/styles.xml:
<resources>
<!-- Base application theme -->
<style name="Theme.FullScreenActivitySimulation" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your theme here -->
<item name="android:colorPrimary">@color/purple_500</item>
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
</style>
<!-- Custom theme for transparent activity -->
<style name="Theme.AppCompat.Transparent" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
</resources>
Define a drawable resource for the gradient border effect.
res/drawable/gradient_stroke.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background color to make the center transparent -->
<item>
<shape android:shape="rectangle">
<solid android:color="#00000000" />
</shape>
</item>
<!-- Top Edge -->
<item>
<shape android:shape="rectangle">
<gradient
android:centerY="0.03"
android:centerColor="@android:color/transparent"
android:startColor="#0000FF"
android:endColor="@android:color/transparent"
android:angle="90" />
</shape>
</item>
<!-- Bottom Edge -->
<item android:bottom="0dp">
<shape android:shape="rectangle">
<gradient
android:centerY="0.97"
android:centerColor="@android:color/transparent"
android:endColor="#0000FF"
android:startColor="@android:color/transparent"
android:angle="90" />
</shape>
</item>
<!-- Left Edge -->
<item>
<shape android:shape="rectangle">
<gradient
android:centerX="0.03"
android:centerColor="@android:color/transparent"
android:startColor="#0000FF"
android:endColor="@android:color/transparent"
android:angle="0" />
</shape>
</item>
<!-- Right Edge -->
<item android:right="0dp">
<shape android:shape="rectangle">
<gradient
android:centerX="0.97"
android:centerColor="@android:color/transparent"
android:endColor="#0000FF"
android:startColor="@android:color/transparent"
android:angle="0" />
</shape>
</item>
</layer-list>
Create a layout file for the EdgeLightingActivity
that uses the gradient stroke drawable as its background.
res/layout/activity_edge_lighting.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000">
<View
android:id="@+id/edge_lighting_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_stroke" />
</RelativeLayout>
Implement the EdgeLightingActivity
to display the gradient stroke and automatically close after a few seconds.
EdgeLightingActivity.kt:
package com.example.fullscreenactivitysimulation
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
class EdgeLightingActivity : AppCompatActivity() {
private val TAG = "EdgeLightingActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate called")
// Make the activity full-screen using WindowInsetsController
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
setContentView(R.layout.activity_edge_lighting)
// Set a timer to close the activity after a few seconds
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
finish()
}, 3000) // Show the edge lighting for 3 seconds
}
}
Add a Floating Action Button (FAB) in MainActivity
to launch the EdgeLightingActivity
.
MainActivity.kt:
package com.example.fullscreenactivitysimulation
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.icons.Icons
import androidx.compose.material3.icons.filled.Add
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.fullscreenactivitysimulation.ui.theme.FullScreenActivitySimulationTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
FullScreenActivitySimulationTheme {
Scaffold(
modifier = Modifier.fillMaxSize(),
floatingActionButton = {
FloatingActionButton(
onClick = {
val intent = Intent(this, EdgeLightingActivity::class.java)
startActivity(intent)
}
) {
Icon(Icons.Filled.Add, contentDescription = "Localized description")
}
}
) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
FullScreenActivitySimulationTheme {
Greeting("Android")
}
}
Ensure the custom theme is applied to your activity in the manifest file.
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FullScreenActivitySimulation">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.AppCompat.Transparent">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".EdgeLightingActivity"
android:theme="@style/Theme.AppCompat.Transparent" />
</application>
</manifest>
To ensure the gradient border is only viewable for a set amount of time after a button click in Method 2, you can programmatically add the border view, display it for a specified duration, and then remove it.
Here's how to modify the implementation to achieve this:
You can also draw directly to the screen by setting the appropriate theme in the main activity, which controls the total area the app will draw.
Pros:
Cons:
Ensure you have the custom theme defined as shown in Method 1.
Modify your main activity layout to include a FrameLayout
that overlays the gradient border drawable on top of your main content.
<!-- res/layout/activity_main.xml -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Main content goes here -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Your main content here -->
<!-- Example: -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, World!"
android:layout_centerInParent="true" />
</RelativeLayout>
<!-- Gradient border overlay, initially invisible -->
<View
android:id="@+id/gradient_border_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_stroke"
android:visibility="gone" />
<!-- FloatingActionButton to trigger the border display
<com.google.android.material3.FloatingActionButton -->
<!-- FloatingActionButton to trigger the border display -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@android:drawable/ic_input_add" />
</FrameLayout>
Add functionality to display the gradient border for a set amount of time after a button click.
// MainActivity.kt
package com.example.fullscreenactivitysimulation
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : AppCompatActivity() {
private lateinit var gradientBorderView: View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
gradientBorderView = findViewById(R.id.gradient_border_view)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener {
showGradientBorderForLimitedTime(3000) // Show for 3 seconds
}
}
private fun showGradientBorderForLimitedTime(duration: Long) {
gradientBorderView.visibility = View.VISIBLE
Handler(Looper.getMainLooper()).postDelayed({
gradientBorderView.visibility = View.GONE
}, duration)
}
}
Ensure the custom theme is applied to your activity in the manifest file.
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Method 1: Using a Second Activity
Method 2: Drawing Directly to the Main Activity
FrameLayout
and proper theme configuration.By following these steps, you can create a transparent, gradient border directly on your main activity, achieving a clean and integrated effect without the need for a separate activity. The border will only be viewable for a set amount of time after the button is clicked.