{"id":26495179,"url":"https://github.com/luiisca/floating-views","last_synced_at":"2025-03-20T10:37:15.182Z","repository":{"id":244163319,"uuid":"814450362","full_name":"luiisca/floating-views","owner":"luiisca","description":"Kotlin library for effortlessly creating customizable floating UI elements in Android apps.","archived":false,"fork":false,"pushed_at":"2024-09-04T23:10:28.000Z","size":1376,"stargazers_count":4,"open_issues_count":14,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-09-07T06:28:41.040Z","etag":null,"topics":["android-library","floating","jetpack-compose","kotlin-android"],"latest_commit_sha":null,"homepage":"https://central.sonatype.com/artifact/io.github.luiisca/floating.views","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luiisca.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-13T03:30:43.000Z","updated_at":"2024-09-04T23:10:31.000Z","dependencies_parsed_at":"2024-06-13T07:27:14.400Z","dependency_job_id":"a06ed4d7-1f50-4b1f-8099-a99c1ec5f306","html_url":"https://github.com/luiisca/floating-views","commit_stats":null,"previous_names":["luiisca/floaty"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luiisca%2Ffloating-views","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luiisca%2Ffloating-views/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luiisca%2Ffloating-views/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luiisca%2Ffloating-views/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luiisca","download_url":"https://codeload.github.com/luiisca/floating-views/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244598276,"owners_count":20479089,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-library","floating","jetpack-compose","kotlin-android"],"created_at":"2025-03-20T10:37:14.568Z","updated_at":"2025-03-20T10:37:15.175Z","avatar_url":"https://github.com/luiisca.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Latest release](https://img.shields.io/github/v/release/luiisca/floating-views?color=brightgreen\u0026label=latest%20release)](https://github.com/luiisca/floating-views/releases/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n\n\n# 🎈 Floating Views\n\nA Kotlin library for effortlessly creating customizable floating UI elements in Android apps.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/user-attachments/assets/482c11ad-999a-47cd-ba37-a3a3099d67cc\" alt=\"Floating Views Demo\" width=\"300\"/\u003e\n\u003c/p\u003e\n\n## Features\n\n- 🚀 Declarative API using Jetpack Compose for easy integration\n- 🌊 Smooth animations with customizable transition specs\n- 🧲 Smart edge-snapping behavior for improved UX\n- 🎛️ Fine-grained control over float behavior and interactions\n- 📏 Adaptive sizing to fit content and screen dimensions\n- 🔒 Built-in runtime permission handling for overlay views\n- 🎨 Flexible view creation with Jetpack Compose or traditional Views\n- 🔌 Easy service start/stop controls from any part of your app\n\n## Requirements\n\n- Android SDK version 21+\n- Maven central\n\n## Quick Start\n\n### 1. Import to project\n\nAdd the following dependency to your app's `build.gradle.kts` file:\n\n```kotlin\ndependencies {\n    implementation(\"io.github.luiisca.floating.views:1.0.5\")\n}\n```\n\n\u003e [sample/build.gradle.kts:55](https://github.com/luiisca/floating-views/blob/a2a3cc587f5c8eca2b4c80f9aa78b587fab5dd86/sample/build.gradle.kts#L55)\n\n### 2. Update your AndroidManifest.xml\n\nAdd the following to your `AndroidManifest.xml`:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cmanifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\u003e\n\n    \u003c!-- Permission to draw over other apps --\u003e\n    \u003cuses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" /\u003e\n\n    \u003c!-- Permission to run a foreground service --\u003e\n    \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" /\u003e\n\n    \u003c!-- Permission for special use foreground service (Android 14+) --\u003e\n    \u003c!-- You can adjust this based on your use case. See: https://developer.android.com/develop/background-work/services/fg-service-types --\u003e\n    \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE_SPECIAL_USE\" /\u003e\n\n    \u003capplication\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.Sample\"\n        tools:targetApi=\"33\"\u003e\n\n        \u003c!-- Foreground service declaration --\u003e\n        \u003c!-- This service is crucial for drawing content over other apps --\u003e\n        \u003c!-- The foregroundServiceType should match your use case. Options include:\n             - dataSync, mediaPlayback, phoneCall, location, connectedDevice, mediaProjection, camera, microphone\n             - If none of these fit, use \"specialUse\" as shown here --\u003e\n        \u003cservice\n            android:name=\".Service\"\n            android:enabled=\"true\"\n            android:foregroundServiceType=\"specialUse\"\u003e\n            \u003c!-- Required for \"specialUse\" type. Describe your use case for app store review --\u003e\n            \u003cproperty\n                android:name=\"android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE\"\n                android:value=\"Describe your special use case here\" /\u003e\n        \u003c/service\u003e\n\n        \u003cactivity\n            android:name=\".MainActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.Sample\"\n            android:windowSoftInputMode=\"adjustResize\"\u003e \u003c!-- insets support --\u003e\n            \u003cintent-filter\u003e\n                \u003caction android:name=\"android.intent.action.MAIN\" /\u003e\n                \u003ccategory android:name=\"android.intent.category.LAUNCHER\" /\u003e\n            \u003c/intent-filter\u003e\n        \u003c/activity\u003e\n    \u003c/application\u003e\n\u003c/manifest\u003e\n```\n\n\u003e [sample/.../AndroidManifest.xml](https://github.com/luiisca/floating-views/blob/a2a3cc587f5c8eca2b4c80f9aa78b587fab5dd86/sample/src/main/AndroidManifest.xml)\n\n### 3. Launch and manage your custom floating view\n\nThis library allows you to create a highly customizable floating view with three main components: main float, close float, and expanded float. Here's how to configure and launch your floating view:\n\n3.1. **Create a custom configuration**: Use `FloatingViewsConfig` to define the behavior of a single floating view and its components.\n\n```kotlin\nval config = FloatingViewsConfig(\n  enableAnimations = true, // Enable or disable animations\n  main = MainFloatConfig(\n    composable = { YourMainFloatContent() },\n    // Configure main float behavior\n  ),\n  close = CloseFloatConfig(\n    composable = { YourCloseFloatContent() },\n    // Configure close float behavior\n  ),\n  expanded = ExpandedFloatConfig(\n    composable = { close -\u003e YourExpandedFloatContent(close) },\n    // Configure expanded float behavior\n  )\n)\n```\n\nEach config object (`MainFloatConfig`, `CloseFloatConfig`, `ExpandedFloatConfig`) allows you to customize various aspects of that specific component of your floating view.\n\n3.2. **Launch the floating view**: Use `FloatingViewsManager.startFloatServiceIfPermitted()` to start the service and display your custom floating view.\n\n```kotlin\nFloatingViewsManager.startFloatServiceIfPermitted(context, config)\n```\n\n3.3 **Monitor service state**: Subscribe to `FloatServiceStateManager.isServiceRunning` to be notified when the service starts or stops.\n\n```kotlin\n@Composable\nfun YourComposable() {\n\tval isServiceRunning by FloatServiceStateManager.isServiceRunning.collectAsState()\n\n    // Use isServiceRunning to update your UI\n    if (isServiceRunning) {\n        Text(\"Service is running\")\n    } else {\n        Text(\"Service is not running\")\n    }\n}\n```\n\u003cdetails\u003e\n\t\u003csummary\u003eHere's an example demonstrating how to create and launch multiple, distinct floating views while monitoring the service state:\u003c/summary\u003e\n\n```kotlin\n@Composable\nfun App() {\n  Scaffold { innerPadding -\u003e\n    println(innerPadding)\n\n    val context = LocalContext.current\n    val isServiceRunning by FloatServiceStateManager.isServiceRunning.collectAsState()\n\n    Column(\n      modifier = Modifier\n        .fillMaxSize()\n        .padding(16.dp),\n      verticalArrangement = Arrangement.Center,\n      horizontalAlignment = Alignment.CenterHorizontally\n    ) {\n      // Base Float\n      Button(\n        modifier = Modifier.widthIn(min = 200.dp, max = 300.dp),\n        onClick = {\n          val config = FloatingViewsConfig(\n            enableAnimations = false,\n            main = MainFloatConfig(\n              composable = { BaseFloat() },\n              // Add other main float configurations here\n            ),\n            close = CloseFloatConfig(\n              closeBehavior = CloseBehavior.CLOSE_SNAPS_TO_MAIN_FLOAT,\n              // Add other close float configurations here\n            ),\n            expanded = ExpandedFloatConfig(\n              composable = {close -\u003e BaseExpandedFloat(close) },\n              // Add other expanded float configurations here\n            )\n          )\n\n          // Launch a new music player floating view\n          FloatingViewsManager.startFloatServiceIfPermitted(context, config)\n        }\n      ) {\n        Text(text = \"Base\", style = MaterialTheme.typography.bodyLarge)\n      }\n\n      // ...\n\n      // Display a button to stop the service if it's running\n      if (isServiceRunning) {\n        Spacer(modifier = Modifier.height(16.dp))\n        Button(\n          colors = ButtonDefaults.buttonColors(\n            containerColor = MaterialTheme.colorScheme.error,\n            contentColor = MaterialTheme.colorScheme.onError\n          ),\n          modifier = Modifier.widthIn(min = 200.dp, max = 300.dp),\n          onClick = {\n            FloatingViewsManager.stopFloatService(context)\n          }\n        ) {\n          Text(text = \"Remove all\", style = MaterialTheme.typography.bodyLarge)\n        }\n      }\n    }\n  }\n}\n```\n\n\u003e [sample/.../App.kt](https://github.com/luiisca/floating-views/blob/a2a3cc587f5c8eca2b4c80f9aa78b587fab5dd86/sample/src/main/kotlin/com/sample/app/App.kt#L38)\n\n\u003c/details\u003e\n\n## Customization\n\nThe `FloatingViewsController` offers extensive customization options. Here's an overview of key features, followed by a complete reference.\n\n### Key Customization Examples\n\n1. Main Floating View:\n\n```kotlin\nval mainFloatConfig = MainFloatConfig(\n    composable = { /* Your content */ },\n    startPointDp = PointF(100f, 100f),\n    isSnapToEdgeEnabled = true,\n    onTap = { /* Handle tap */ }\n)\n```\n\n2. Expanded View:\n\n```kotlin\nval expandedFloatConfig = ExpandedFloatConfig(\n    enabled = true,\n    tapOutsideToClose = true,\n    dimAmount = 0.5f,\n    composable = { close -\u003e /* Expanded content */ }\n)\n```\n\n3. Close View:\n\n```kotlin\nval closeFloatConfig = CloseFloatConfig(\n    enabled = true,\n    composable = { /* Custom close button */ },\n    closeBehavior = CloseBehavior.MAIN_SNAPS_TO_CLOSE_FLOAT\n)\n```\n\n### Complete Configuration Reference\n\nBelow is a comprehensive list of all configuration options:\n\n#### MainFloatConfig\n\n| Option                      | Description                                                                                                                                                                                      | Type                                                                                             | Default                                                                                      |\n| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |\n| `composable`                | The Composable to be rendered inside the floating view. If null, `viewFactory` is used.                                                                                                          | `(@Composable () -\u003e Unit)?`                                                                      | `null`                                                                                       |\n| `viewFactory`               | Factory function to create a traditional Android view inside the floating view. If null, `composable` is used.                                                                                   | `((Context) -\u003e View)?`                                                                           | `null`                                                                                       |\n| `startPointDp`              | Initial position of the floating view in density-independent pixels (dp). When neither `startPointDp` nor `startPointPx` are provided `PointF(0,0)` is used.                                     | `PointF?`                                                                                        | `null`                                                                                       |\n| `startPointPx`              | Initial position of the floating view in pixels (px). When neither `startPointDp` nor `startPointPx` are provided `PointF(0,0)` is used.                                                         | `PointF?`                                                                                        | `null`                                                                                       |\n| `draggingTransitionSpec`    | Animation spec for dragging transitions. Applied when `FloatingViewsController.enableAnimations` is `true`.                                                                                      | `(Transition.Segment\u003cPoint\u003e.() -\u003e FiniteAnimationSpec\u003cInt\u003e)`                                     | `spring(dampingRatio = Spring.DampingRatioNoBouncy, stiffness = Spring.StiffnessHigh)`       |\n| `snapToEdgeTransitionSpec`  | Animation spec for snapping to the screen edge. Applied when `FloatingViewsController.enableAnimations` is `true` and `isSnapToEdgeEnabled` is `true`.                                           | `(Transition.Segment\u003cPoint\u003e.() -\u003e FiniteAnimationSpec\u003cInt\u003e)`                                     | `spring(dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessMedium)` |\n| `snapToCloseTransitionSpec` | Animation spec for snapping to close float. Applied when `FloatingViewsController.enableAnimations` is `true` and `CloseFloatConfig.closeBehavior` is `CloseBehavior.MAIN_SNAPS_TO_CLOSE_FLOAT`. | `(Transition.Segment\u003cPoint\u003e.() -\u003e FiniteAnimationSpec\u003cInt\u003e)`                                     | `spring(dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow)`    |\n| `isSnapToEdgeEnabled`       | If `true`, the floating view will snap to the nearest screen edge when dragging ends.                                                                                                            | `Boolean`                                                                                        | `true`                                                                                       |\n| `onTap`                     | Callback triggered when the floating view is tapped.                                                                                                                                             | `((Offset) -\u003e Unit)?`                                                                            | `null`                                                                                       |\n| `onDragStart`               | Callback triggered when dragging of the floating view begins.                                                                                                                                    | `((offset: Offset) -\u003e Unit)?`                                                                    | `null`                                                                                       |\n| `onDrag`                    | Callback triggered during dragging of the floating view.                                                                                                                                         | `((PointerInputChange, dragAmount: Offset, newPoint: Point, newAnimatedPoint: Point?) -\u003e Unit)?` | `null`                                                                                       |\n| `onDragEnd`                 | Callback triggered when dragging of the floating view ends.                                                                                                                                      | `(() -\u003e Unit)?`                                                                                  | `null`                                                                                       |\n\n#### ExpandedFloatConfig\n\n| Option                              | Description                                                                                                                                        | Type                                              | Default |\n| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ------- |\n| `enabled`                           | If `true`, enables expanded view mode.                                                                                                             | `Boolean`                                         | `true`  |\n| `tapOutsideToClose`                 | If `true` adds an overlay view that will close expanded view when tapped.                                                                          | `Boolean`                                         | `true`  |\n| `dimAmount`                         | Controls the dimming amount of the background when the view is expanded. Range is from 1.0 for completely opaque to 0.0 for no dim.                | `Float`                                           | `0.5f`  |\n| `composable`                        | The Composable to be rendered inside the expanded view. If null, `viewFactory` is used. Call close to remove expanded view.                        | `(@Composable (close: () -\u003e Unit) -\u003e Unit)?`      | `null`  |\n| `viewFactory`                       | Factory function to create a traditional Android view inside the expanded view. If null, `composable` is used. Call close to remove expanded view. | `((context: Context, close:() -\u003e Unit) -\u003e View)?` | `null`  |\n| All properties from MainFloatConfig | All properties from `MainFloatConfig` are also available here.                                                                                     |                                                   |         |\n\n#### CloseFloatConfig\n\n| Option                     | Description                                                                                                                                                                                                                              | Type                                                         | Default                                                                                |\n| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- |\n| `enabled`                  | If `true`, enables the close float behavior.                                                                                                                                                                                             | `Boolean`                                                    | `true`                                                                                 |\n| `composable`               | The Composable to be rendered inside the close floating view. If null, `viewFactory` is used.                                                                                                                                            | `(@Composable () -\u003e Unit)?`                                  | `null`                                                                                 |\n| `viewFactory`              | Factory function to create a traditional Android view inside the close floating view. If null, `composable` is used.                                                                                                                     | `((Context) -\u003e View)?`                                       | `null`                                                                                 |\n| `startPointDp`             | Initial position of the close floating view in density-independent pixels (dp). When neither `startPointDp` nor `startPointPx` are provided `PointF(0,0)` is used.                                                                       | `PointF?`                                                    | `null`                                                                                 |\n| `startPointPx`             | Initial position of the close float in pixels (px). When neither `startPointDp` nor `startPointPx` are provided `PointF(0,0)` is used.                                                                                                   | `PointF?`                                                    | `null`                                                                                 |\n| `mountThresholdDp`         | Dragging distance required to show the close float, in density-independent pixels (dp). When neither `mountThresholdDp` nor `mountThresholdPx` are provided `1.dp` is used.                                                              | `Float?`                                                     | `null`                                                                                 |\n| `mountThresholdPx`         | Dragging distance required to show the close float, in pixels (px). When neither `mountThresholdDp` nor `mountThresholdPx` are provided `1.                                                                                              | `Float?`                                                     | `null`                                                                                 |\n| `closingThresholdDp`       | Dragging distance (in density-independent pixels) between the main float and the close float that triggers a `CloseFloatConfig.closeBehavior`. When neither `closingThresholdDp` nor `closingThresholdPx` are provided `100.dp` is used. | `Float?`                                                     | `null`                                                                                 |\n| `closingThresholdPx`       | Dragging distance (in pixels) between the main float and the close float that triggers a `CloseFloatConfig.closeBehavior`. When neither `closingThresholdDp` nor `closingThresholdPx` are provided `100.dp` is used.                     | `Float?`                                                     | `null`                                                                                 |\n| `bottomPaddingDp`          | Bottom padding for the close float in density-independent pixels (dp). When neither `bottomPaddingDp` nor `bottomPaddingPx` are provided `16.dp` is used.                                                                                | `Float?`                                                     | `null`                                                                                 |\n| `bottomPaddingPx`          | Bottom padding for the close float in pixels (px). When neither `bottomPaddingDp` nor `bottomPaddingPx` are provided `16.dp` is used.                                                                                                    | `Float?`                                                     | `null`                                                                                 |\n| `draggingTransitionSpec`   | Animation specification for dragging. Applied when `FloatingViewsController.enableAnimations` is `true` and `CloseFloatConfig.closeBehavior` is `CloseBehavior.CLOSE_SNAPS_TO_MAIN_FLOAT`.                                               | `(Transition.Segment\u003cPoint\u003e.() -\u003e FiniteAnimationSpec\u003cInt\u003e)` | `spring(dampingRatio = Spring.DampingRatioNoBouncy, stiffness = Spring.StiffnessHigh)` |\n| `snapToMainTransitionSpec` | Animation specification for snapping to main float. Applied when `FloatingViewsController.enableAnimations` is `true` and `CloseFloatConfig.closeBehavior` is `CloseBehavior.CLOSE_SNAPS_TO_MAIN_FLOAT`.                                 | `(Transition.Segment\u003cPoint\u003e.() -\u003e FiniteAnimationSpec\u003cInt\u003e)` | `spring(dampingRatio = Spring.DampingRatioLowBouncy, stiffness = Spring.StiffnessLow)` |\n| `closeBehavior`            | Determines how the close float interacts with the main float.                                                                                                                                                                            | `CloseBehavior?`                                             | `CloseBehavior.MAIN_SNAPS_TO_CLOSE_FLOAT`                                              |\n| `followRate`               | Defines the rate at which the close float follows the main float when dragged. Only used when `CloseFloatConfig.closeBehavior` is `CloseBehavior.CLOSE_SNAPS_TO_MAIN_FLOAT`.                                                             | `Float`                                                      | `0.1f`                                                                                 |\n\n## Contributing\n\nFound a bug? Have a cool idea? Feel free to open an issue or submit a PR. We're all friends here!\n\nHappy floating! 🎈\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluiisca%2Ffloating-views","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluiisca%2Ffloating-views","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluiisca%2Ffloating-views/lists"}