Skip to content

feat: add dimmedAlpha prop #151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 84 additions & 8 deletions android/src/main/java/com/lodev09/truesheet/TrueSheetDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package com.lodev09.truesheet

import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import com.facebook.react.uimanager.ThemedReactContext
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
Expand All @@ -23,6 +25,9 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
private var keyboardManager = KeyboardManager(reactContext)
private var windowAnimation: Int = 0

// Custom dimming overlay view
private var dimmingView: View? = null

// First child of the rootSheetView
private val containerView: ViewGroup?
get() = if (rootSheetView.childCount > 0) {
Expand All @@ -39,13 +44,28 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
* Set to `false` to allow interaction with the background components.
*/
var dimmed = true
set(value) {
field = value
updateDimmingView()
}

/**
* The size index that the sheet should start to dim the background.
* This is ignored if `dimmed` is set to `false`.
*/
var dimmedIndex = 0

/**
* The alpha value of the dimmed background.
*
* @default 0.75f
*/
var dimmedAlpha = 0.75f
set(value) {
field = value
updateDimmingView()
}

/**
* The maximum window height
*/
Expand Down Expand Up @@ -93,12 +113,58 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
window?.apply {
// Store current windowAnimation value to toggle later
windowAnimation = attributes.windowAnimations

// Disable default dimming
clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
}

// Create and add our custom dimming view
createDimmingView()

// Update the usable sheet height
maxScreenHeight = Utils.screenHeight(reactContext, edgeToEdge)
}

/**
* Create and add a custom dimming view to the dialog
*/
private fun createDimmingView() {
// Get the content view of the dialog
val decorView = window?.decorView as? ViewGroup
val contentView = decorView?.findViewById<FrameLayout>(android.R.id.content)

// Create a new view for dimming
dimmingView = View(context).apply {
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
background = ColorDrawable(Color.BLACK)
alpha = if (dimmed) dimmedAlpha else 0f
visibility = if (dimmed) View.VISIBLE else View.GONE
elevation = -1f // Make sure it's below other content

// Add the view at index 0 so it's behind everything else
contentView?.addView(this, 0)

// Make sure it's behind the sheet
bringToFront()
}

// Make sure the sheet is on top of the dimming view
rootSheetView.bringToFront()
}

/**
* Update the dimming view based on current settings
*/
private fun updateDimmingView() {
dimmingView?.apply {
alpha = if (dimmed) dimmedAlpha else 0f
visibility = if (dimmed) View.VISIBLE else View.GONE
}
}

override fun getEdgeToEdgeEnabled(): Boolean = edgeToEdge || super.getEdgeToEdgeEnabled()

override fun onStart() {
Expand All @@ -114,6 +180,9 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
}
}

// Make sure dimming is applied
updateDimmingView()
}

/**
Expand Down Expand Up @@ -150,11 +219,9 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
// Remove touch listener
view.setOnTouchListener(null)

// Add the dimmed background
setFlags(
WindowManager.LayoutParams.FLAG_DIM_BEHIND,
WindowManager.LayoutParams.FLAG_DIM_BEHIND
)
// Show dimming view with the specified alpha
dimmingView?.visibility = View.VISIBLE
dimmingView?.alpha = dimmedAlpha

setCanceledOnTouchOutside(dismissible)
} else {
Expand All @@ -165,8 +232,8 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
false
}

// Remove the dimmed background
clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
// Hide our custom dimming view
dimmingView?.visibility = View.GONE

setCanceledOnTouchOutside(false)
}
Expand All @@ -183,11 +250,12 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
* Present the sheet.
*/
fun present(sizeIndex: Int, animated: Boolean = true) {
setupDimmedBackground(sizeIndex)
if (isShowing) {
setupDimmedBackground(sizeIndex)
setStateForSizeIndex(sizeIndex)
} else {
configure()
setupDimmedBackground(sizeIndex)
setStateForSizeIndex(sizeIndex)

if (!animated) {
Expand All @@ -196,6 +264,14 @@ class TrueSheetDialog(private val reactContext: ThemedReactContext, private val
}

show()

// Ensure dimming is applied after showing
if (dimmed && sizeIndex >= dimmedIndex) {
dimmingView?.visibility = View.VISIBLE
dimmingView?.alpha = dimmedAlpha
} else {
dimmingView?.visibility = View.GONE
}
}
}

Expand Down
10 changes: 6 additions & 4 deletions android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ class TrueSheetView(context: Context) :
}

currentSizeIndex = it.index
sheetDialog.setupDimmedBackground(it.index)

// Dispatch onSizeChange event
dispatchEvent(TrueSheetEvent.SIZE_CHANGE, sizeInfoData(it))
Expand Down Expand Up @@ -357,9 +356,12 @@ class TrueSheetView(context: Context) :
if (sheetDialog.dimmed == dimmed) return

sheetDialog.dimmed = dimmed
if (sheetDialog.isShowing) {
sheetDialog.setupDimmedBackground(currentSizeIndex)
}
}

fun setDimmedAlpha(alpha: Float) {
if (sheetDialog.dimmedAlpha == alpha) return

sheetDialog.dimmedAlpha = alpha
}

fun setDimmedIndex(index: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ class TrueSheetViewManager : ViewGroupManager<TrueSheetView>() {
view.setDimmed(dimmed)
}

@ReactProp(name = "dimmedAlpha")
fun setDimmedAlpha(view: TrueSheetView, alpha: Float) {
view.setDimmedAlpha(alpha)
}

@ReactProp(name = "initialIndex")
fun setInitialIndex(view: TrueSheetView, index: Int) {
view.initialIndex = index
Expand Down
38 changes: 38 additions & 0 deletions ios/TrueSheetView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

@objc(TrueSheetView)
class TrueSheetView: UIView, RCTInvalidating, TrueSheetViewControllerDelegate {
// MARK: - Static properties

// Keep track of active sheet opacity values (stack)
private static var sheetOpacityStack: [CGFloat] = []

// MARK: - React properties

// MARK: - Events
Expand All @@ -25,6 +30,7 @@ class TrueSheetView: UIView, RCTInvalidating, TrueSheetViewControllerDelegate {

@objc var initialIndex: NSNumber = -1
@objc var initialIndexAnimated = true
@objc var dimmedAlpha: CGFloat = 0.75

// MARK: - Private properties

Expand Down Expand Up @@ -195,6 +201,18 @@ class TrueSheetView: UIView, RCTInvalidating, TrueSheetViewControllerDelegate {
}

func viewControllerWillAppear() {
// Only apply dimming if the sheet has dimmed property set to true
if viewController.dimmed {
let opacity = 1 - dimmedAlpha
// Add this sheet's opacity to the stack and dim root view controller
TrueSheetView.sheetOpacityStack.append(opacity)
UIView.animate(withDuration: 0.3) {
if let rootViewController = UIApplication.shared.windows.first?.rootViewController {
rootViewController.view.alpha = opacity
}
}
}

guard let contentView, let scrollView, let containerView else {
return
}
Expand All @@ -204,6 +222,26 @@ class TrueSheetView: UIView, RCTInvalidating, TrueSheetViewControllerDelegate {
scrollView.pinTo(view: contentView, constraints: nil)
}

func viewControllerWillDisappear() {
if viewController.isBeingDismissed && viewController.dimmed {
if !TrueSheetView.sheetOpacityStack.isEmpty {
TrueSheetView.sheetOpacityStack.removeLast()
}

UIView.animate(withDuration: 0.3) {
if let rootViewController = UIApplication.shared.windows.first?.rootViewController {
// If there are still active sheets, apply the alpha of the topmost one
if let topmostOpacity = TrueSheetView.sheetOpacityStack.last {
rootViewController.view.alpha = topmostOpacity
} else {
// If no sheets are left, restore alpha to 1
rootViewController.view.alpha = 1
}
}
}
}
}

func viewControllerDidDismiss() {
isPresented = false
activeIndex = nil
Expand Down
6 changes: 6 additions & 0 deletions ios/TrueSheetViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ protocol TrueSheetViewControllerDelegate: AnyObject {
func viewControllerDidDismiss()
func viewControllerDidChangeSize(_ sizeInfo: SizeInfo?)
func viewControllerWillAppear()
func viewControllerWillDisappear()
func viewControllerKeyboardWillShow(_ keyboardHeight: CGFloat)
func viewControllerKeyboardWillHide()
func viewControllerDidDrag(_ state: UIPanGestureRecognizer.State, _ height: CGFloat)
Expand Down Expand Up @@ -144,6 +145,11 @@ class TrueSheetViewController: UIViewController, UISheetPresentationControllerDe
delegate?.viewControllerWillAppear()
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
delegate?.viewControllerWillDisappear()
}

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
delegate?.viewControllerDidDismiss()
Expand Down
1 change: 1 addition & 0 deletions ios/TrueSheetViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ @interface RCT_EXTERN_REMAP_MODULE (TrueSheetView, TrueSheetViewManager, RCTView
RCT_EXPORT_VIEW_PROPERTY(dimmedIndex, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(initialIndex, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(initialIndexAnimated, BOOL)
RCT_EXPORT_VIEW_PROPERTY(dimmedAlpha, CGFloat)

// Internal properties
RCT_EXPORT_VIEW_PROPERTY(contentHeight, NSNumber)
Expand Down
2 changes: 2 additions & 0 deletions src/TrueSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
keyboardMode = 'resize',
initialIndex,
dimmedIndex,
dimmedAlpha = 0.75,
grabberProps,
blurTint,
cornerRadius,
Expand All @@ -276,6 +277,7 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
grabber={grabber}
dimmed={dimmed}
dimmedIndex={dimmedIndex}
dimmedAlpha={dimmedAlpha}
edgeToEdge={edgeToEdge}
initialIndex={initialIndex}
initialIndexAnimated={initialIndexAnimated}
Expand Down
7 changes: 7 additions & 0 deletions src/TrueSheet.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ export interface TrueSheetProps extends ViewProps {
*/
dimmedIndex?: number

/**
* The alpha value of the dimmed background.
*
* @default 0.75
*/
dimmedAlpha?: number

/**
* Prevents interactive dismissal of the Sheet.
*
Expand Down