So I have a DialogFragment which I want it to be cancelable, the thing is that I need to apply match_parent as width and height to see the dialog in the screen well formated , but when clicking outside it does not dismiss the dialog
class InformationDialogFragment : DialogFragment() {
lateinit var viewState: InformationDialogViewState
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.ModalTheme)
}
override fun onStart() {
super.onStart()
val dialog = dialog
if (dialog != null) {
val width = ViewGroup.LayoutParams.MATCH_PARENT
val height = ViewGroup.LayoutParams.MATCH_PARENT
dialog.window!!.setLayout(width, height)
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = Dialog(requireContext(), R.style.MyDialog)
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog.window?.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN)
return dialog
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
val binding: InformationDialogBinding = DataBindingUtil.inflate(inflater, R.layout.account_information_dialog, container, false)
binding.viewState = viewState
return binding.root
}
}
I don't need to put isCancelable, setCancelableOnTouch, setCancelable because the dialog itself is cancealable as default, and I have tried it all
when I remove the onStart code, the touch outside works and dismisses the dialog, but the dialog is all shown wrong and vertically
Changing height to wrap content let me dismiss the dialog clicking outside of it
override fun onStart() {
super.onStart()
val dialog = dialog
if (dialog != null) {
val width = ViewGroup.LayoutParams.MATCH_PARENT
val height = ViewGroup.LayoutParams.WRAP_CONTENT
dialog.window!!.setLayout(width, height)
}
}
Related
I have a custom dialog in kotlin fragment which have 2 button and a progress bar in fuction submitSpk()
class RincianPembelianFragment : androidx.fragment.app.Fragment(), BlockingStep {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.fragment_spk_rincian_bayar, container, false)
//initialize your UI
return v
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.supportFragmentManager?.popBackStack(null, androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE)
setContext(activity!!.applicationContext)
}
fun submitSpks (){
val inflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val builder = AlertDialog.Builder(context!!)
val dialogView = inflater.inflate(R.layout.activity_signature, null)
builder.setView(dialogView)
builder.setTitle("Tanda Tangan Pembeli")
//builder.show()
builder.setCancelable(false)
dialogView.clear.setOnClickListener {
dialogView.signature_view.clearCanvas()
}
dialogView.save.setOnClickListener {
submitTtd() // or some fuction else
dialogView.save.visibility = View.INVISIBLE
dialogView.progressBar.visibility = View.VISIBLE
}
builder.setNegativeButton(""){ dialog: DialogInterface?, which: Int ->
}
builder.show()
}
fun submitTtd(){
// here there will be a crud transaction and visible/invisible button save
}
}
my custom dialog is look like this
i want to visibility gone the button save dialogView.save.visibility = View.VISIBLE from another fuction e.g saveTtd()
how can i do this? i have tried this but my dialog can't show.. anyone can help me? Thanks before
Storing the dialogView in a global variable should do the job.
Also, call the build() method on the AlertDialog.Builder instance before showing the dialog:
class RincianPembelianFragment : androidx.fragment.app.Fragment(), BlockingStep {
private lateinit var dialogView: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val v = inflater.inflate(R.layout.fragment_spk_rincian_bayar, container, false)
//initialize your dialog view
dialogView = inflater.inflate(R.layout.activity_signature, null)
return v
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.supportFragmentManager?.popBackStack(null, androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE)
setContext(activity!!.applicationContext)
}
fun submitSpks() {
// Using requireContext() is suggested
val builder = AlertDialog.Builder(requireContext())
builder.setView(dialogView)
builder.setTitle("Tanda Tangan Pembeli")
builder.setCancelable(false)
dialogView.clear.setOnClickListener {
dialogView.signature_view.clearCanvas()
}
dialogView.save.setOnClickListener {
submitTtd() // or some fuction else
}
builder.setNegativeButton(""){ dialog: DialogInterface?, which: Int ->
}
// Build the dialog builder before showing it
val dialog = builder.build()
dialog.show()
}
fun submitTtd(){
// here there will be a crud transaction and visible/invisible button save
dialogView.save.visibility = View.INVISIBLE
dialogView.progressBar.visibility = View.VISIBLE
}
}
I created a bottom sheet dialog and am implementing cancel function.
It has to be not dismissed when outside of the dialog is touched, but the bottom navigation should catch the touch. After a long trial, I realized I cannot use "setCanceledOnTouchOutside" on Kotlin. "isCancelable=false" is working but cannot use backbutton on the bottom navigation. How should I do if I want to make the bottom navigation touchable only?
Any help will be greatly appreciated
My code is here
class BiometricChangeDetectDialog: BottomSheetDialogFragment() {
private var _binding: DialogBiometricChangeDetectBinding? = null
private val binding get() = _binding!!
private lateinit var mContext: MainActivity
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context as MainActivity
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AlertDialog.Builder(requireContext()).apply {
isCancelable = false
//change here to setCanceledOnTouchOutside
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
_binding = DialogBiometricChangeDetectBinding.inflate(inflater, container, false)
val view = binding.root
binding.btnEmail.setOnClickListener {
dismiss()
findNavController().navigate(R.id.action_biometricChangeDetectDialog_to_biometricChangeEmailDialog)
}
binding.btnSms.setOnClickListener {
dismiss()
findNavController().navigate(R.id.action_biometricChangeDetectDialog_to_biometricChangeEmailDialog)
}
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
add this line in onCreateView
dialog?.setCanceledOnTouchOutside(false)
I want to set the drawable of a ImageView and a ProgressBar in a DialogFragment at runtime. Therefore i want to set the drawable in the onViewCreated and set the ProgressBar visible when the Positive Button of the Dialog is clicked.
But for reasons i do not know absolutely nothing happens. i also tried to call invalidate on the view to actively trigger a redraw but also nothing happens.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.dialog_view, container, false)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val inflater = requireActivity().layoutInflater
val layout = inflater.inflate(R.layout.dialog_view, null)
val dialog = AlertDialog.Builder(requireContext())
.setTitle(R.string.dialog_title)
.setMessage(R.string.dialog_text)
.setView(layout)
.setPositiveButton(R.string.start, null)
.setNegativeButton(R.string.cancel, null)
.create()
return dialog
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
imageView.setImageDrawable(image) //image is a drawable
}
override fun onResume() {
super.onResume()
val d = dialog as AlertDialog?
d?.getButton(Dialog.BUTTON_POSITIVE)?.setOnClickListener {
progressBar.visibility = View.VISIBLE
}
}
Edit:
Found out that if i directly call something on the layout i pass to the dialog it is possible to change visibility of views.
val layout = inflater.inflate(R.layout.dialog_view, null)
layout.findViewById ....
This works but i still wonder why i cannot simply call with kotlin synthetics on the view.
The action that you want to be performed when the positive button is pressed should be added in the dialog build
.setPositiveButton(R.string.start){ _, _ ->
progressBar.visibility = View.VISIBLE
}
As you can see in the image , red border rectangle is the parent activity . Blue one is dialog fragment . The circle is indicating a view and rectangle below is the description. I want the click on circle to be passed down to the button. So far i have tried
1. overriding onTouchEvent in Circle View and return false
2. setOntouchListener on circle view and call activity.dispatchTouchListener and return false
3. mark dialog frgament and circle view clickable/focusable false.
None of the above seems to be calling onCLickListener of the button underneath. I can see touch event being received in Activity's onIterceptTouch() though. Please help
Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val viewTreeObserver = button2.viewTreeObserver
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {MainFragment.newInstance(button2).show(supportFragmentManager, "dialog")
button1.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
container.setOnClickListener {
Log.d("Test","Activity clicked")
}
button.setOnClickListener {
Log.d("Test","Button Clicked")
}
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
Log.d("Test","Activity onTouchEvent")
return super.onTouchEvent(event)
}
}
Dialog Fragment
class MainFragment : DialogFragment() {
companion object {
fun newInstance(view: View?) : MainFragment {
val args = Bundle()
val point = getRippleLocation(getViewCenterLocation(view))
args.putInt("X", point.x)
args.putInt("Y", point.y)
val frag = MainFragment()
frag.arguments = args
return frag
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.main_fragment, container, false)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
dialog.window!!.setGravity(Gravity.START or Gravity.TOP)
point.x = arguments!!.getInt("X")
point.y = arguments!!.getInt("Y")
params.x = point.x
params.y = (point.y - 50)
dialog.window!!.attributes = params
return dialog
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
addRippleView(main, 0, 0)
}
private fun addCircleView(rootView: ViewGroup, leftMargin: Int, topMargin: Int) {
val rippleView = BaseCircleView(context, null)
rippleView.isClickable = false
rippleView.isFocusable = false
rippleView.setOnTouchListener(object : View.OnTouchListener{
override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
activity!!.dispatchTouchEvent(p1)
return false
}
})
configureRipple(rippleView)
context?.resources?.let { resources ->
rippleView.id = R.id.gather_ripple_view_id
val params = RelativeLayout.LayoutParams(resources.getDimensionPixelSize(R.dimen.gather_on_boarding_ripple_container_width),
resources.getDimensionPixelSize(R.dimen.gather_on_boarding_ripple_container_height))
params.leftMargin = leftMargin
params.topMargin = topMargin
rootView.addView(rippleView, params)
}
}
}
If someone is still struggling with this one, this is how is solved it.
dialog?.window?.decorView?.setOnTouchListener { v, event ->
activity?.dispatchTouchEvent(event)
false
}
this will pass touch event through
setting the FLAG_NOT_TOUCH_MODAL worked for me.
Window window = dialog.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
I want to change brightness of my screen when I'm opening some fragment which placed in my activity so I placed so code for this in onActivityCreated (I also tried to placed it onResume). But I want to return my screen to previous brightness when user is closing this fragment. But for now brightness applies for all activity. How to apply brittleness only for fragment? Or record brightness result and retrun it, when fragment is closed?
class BrightnessFragment : Fragment(), Injectable {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
appCompatActivity = activity as AppCompatActivity
val lp = activity!!.window.attributes
lp.screenBrightness = 1F
activity!!.window.attributes = lp
}
override fun onResume() {
super.onResume()
}
}
You could store the previous brightness in a variable within the Fragment. When the Fragment is being removed, it will call onDestroy(), which is a good time to reset the brightness.
And as a side note, when you're writing in Kotlin, try to refrain from using !!. You should handle the case gracefully if it's null. With a ?.let, you can write it so it will only change the brightness if the Activity is not null (it is the Activity in this case).
class BrightnessFragment : Fragment(), Injectable {
companion object {
// Using a constant to make the code cleaner.
private const val MAX_BRIGHTNESS = 1F
}
// Our stored previous brightness.
private var previousBrightness = MAX_BRIGHTNESS
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
(activity as? AppCompatActivity)?.let {
val attributes = it.window.attributes
// Store the previous brightness
previousBrightness = attributes.screenBrightness
// Set the brightness to MAX_BRIGHTNESS.
attributes.screenBrightness = MAX_BRIGHTNESS
it.window.attributes = attributes
}
}
override fun onDestroy() {
(activity as? AppCompatActivity)?.let {
val attributes = it.window.attributes
// Set the brightness to previousBrightness.
attributes.screenBrightness = previousBrightness
it.window.attributes = attributes
}
// Don't forget to called super.onDestroy()
super.onDestroy()
}
}