Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Bottom sheet dialog with dim and blur background, and curved corners. works with BlurKit (https://github.com/CameraKit/blurkit-android) and Anko (https://github.com/Kotlin/anko)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_white_ffffff" />
<corners
android:topLeftRadius="@dimen/dimen16dp"
android:topRightRadius="@dimen/dimen16dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
style="@style/MatchWidthMatchHeight"
android:fitsSystemWindows="true">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
style="@style/MatchWidthMatchHeight"
android:elevation="1dp"
android:fitsSystemWindows="true">
<io.alterac.blurkit.BlurLayout
android:id="@+id/touch_outside_blur_layout"
style="@style/BlurLayoutFullScreen"
android:importantForAccessibility="no"
android:soundEffectsEnabled="false" />
<View
style="@style/MatchWidthMatchHeight"
android:background="@color/color_light_black"
android:importantForAccessibility="no"
android:soundEffectsEnabled="false" />
<FrameLayout
android:id="@+id/bottom_sheet"
style="?attr/bottomSheetStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
android:elevation="@dimen/dimen50dp"
app:layout_behavior="@string/bottom_sheet_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>
//TODO: add package info here
import android.os.Bundle
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.FrameLayout
import androidx.annotation.LayoutRes
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import com.gdn.offline.events.R
import com.gdn.offline.events.base.util.animate
import com.gdn.offline.events.base.util.beginBlur
import com.gdn.offline.events.base.util.then
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
import io.alterac.blurkit.BlurLayout
import org.jetbrains.anko.find
import org.jetbrains.anko.sdk27.coroutines.onClick
/**
* Prem's creation, on 18/03/19
*/
abstract class BlurBottomSheet : DialogFragment() {
@Suppress("PropertyName")
abstract val TAG: String
private lateinit var bottomSheet: FrameLayout
private lateinit var blurLayout: BlurLayout
private lateinit var behavior: BottomSheetBehavior<FrameLayout>
var isHideable: Boolean = true
var backStackId: Int = -1
private val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == STATE_HIDDEN) {
dismiss()
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(DialogFragment.STYLE_NORMAL, R.style.BlurBottomSheetDialog)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
wrapInBottomSheet()
override fun onStart() {
super.onStart()
blurLayout.beginBlur()
if (behavior.state == BottomSheetBehavior.STATE_HIDDEN) {
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
override fun onStop() {
blurLayout.pauseBlur()
super.onStop()
}
override fun dismiss() {
bottomSheet.animate(R.anim.float_down)?.then { super.dismiss() }
}
private fun wrapInBottomSheet(): View? {
val rootLayout = View.inflate(context, R.layout.design_bottom_sheet_dialog, null)
val coordinatorLayout = rootLayout.find<CoordinatorLayout>(R.id.coordinator)
blurLayout = coordinatorLayout.find(R.id.touch_outside_blur_layout)
bottomSheet = coordinatorLayout.find(R.id.bottom_sheet)
bottomSheet.setBackgroundResource(R.drawable.background_bottom_sheet_white)
behavior = BottomSheetBehavior.from(bottomSheet).apply {
setBottomSheetCallback(bottomSheetCallback)
isHideable = isHideable
}
val bottomSheetView = layoutInflater.inflate(bottomSheetLayout(), coordinatorLayout, false)
if (layoutParams() == null)
bottomSheet.addView(bottomSheetView)
else
bottomSheet.addView(bottomSheetView, layoutParams())
setListeners()
startAnimations(bottomSheet)
return rootLayout
}
private fun startAnimations(bottomSheet: FrameLayout) {
bottomSheet.animate(R.anim.float_up)
}
override fun getTheme(): Int = R.style.BlurBottomSheetDialog
@SuppressLint("ClickableViewAccessibility")
private fun setListeners() {
blurLayout.onClick {
if (isAdded && isHideable) {
dismiss()
}
}
ViewCompat.setAccessibilityDelegate(bottomSheet, object : AccessibilityDelegateCompat() {
override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfoCompat?) {
super.onInitializeAccessibilityNodeInfo(host, info)
if (isHideable) {
info?.addAction(AccessibilityNodeInfo.ACTION_DISMISS)
info?.isDismissable = true
} else {
info?.isDismissable = false
}
}
override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
return if (action == AccessibilityNodeInfo.ACTION_DISMISS && isHideable) {
dismiss()
true
} else super.performAccessibilityAction(host, action, args)
}
})
bottomSheet.setOnTouchListener { _, _ -> true }
}
fun setIsHideable(cancelable: Boolean) {
super.setCancelable(cancelable)
if (isHideable != cancelable) {
isHideable = cancelable
behavior.isHideable = cancelable
}
}
fun show(fragmentManager: FragmentManager) {
backStackId = fragmentManager.beginTransaction()
.add(this, TAG)
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.commit()
}
@LayoutRes
abstract fun bottomSheetLayout(): Int
open fun layoutParams(): ViewGroup.LayoutParams? = null
}
<color name="color_light_black">#99000000</color>
<style name="MatchWidthMatchHeight">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
</style>
<!--Style for the "touch_outside_blur_layout" layout in "design_bottom_sheet_dialog-->
<style name="BlurLayoutFullScreen">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:visibility">invisible</item>
<item name="blk_blurRadius">2</item>
<item name="blk_downscaleFactor">0.12</item>
<item name="blk_fps">0</item>
</style>
<!--Style for BlurBottomSheet-->
<style name="BlurBottomSheetDialog" parent="Theme.AppCompat.Light.Dialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="bottomSheetStyle">@style/AppModalStyle</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
</style>
<style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal">
<item name="android:background">@drawable/background_bottom_sheet_white</item>
</style>
import android.view.View
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import androidx.annotation.AnimRes
import androidx.appcompat.app.AppCompatActivity
import com.gdn.offline.events.base.compoundViews.BlurBottomSheet
/**
* Prem's creation, on 18/03/19
*/
fun View.animate(@AnimRes animResId: Int): Animation? {
clearAnimation()
val animation = AnimationUtils.loadAnimation(context, animResId)
startAnimation(animation)
return animation
}
fun Animation.then(action: () -> Unit) {
setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {}
override fun onAnimationStart(animation: Animation?) {}
override fun onAnimationEnd(animation: Animation?) {
action()
}
})
}
// Extension function for delayed blur of the BlurLayout
fun BlurLayout.beginBlur() {
postDelayed({
visibility = View.VISIBLE
startBlur()
}, 150)
}
fun AppCompatActivity.showBottomSheet(bottomSheet: BlurBottomSheet) {
bottomSheet.show(supportFragmentManager)
}
fun BlurBottomSheet.showBottomSheet(bottomSheet: BlurBottomSheet, dismissCurrent: Boolean = true) {
if (dismissCurrent) dismiss()
bottomSheet.show(activity!!.supportFragmentManager)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.