My applications have a Toast. But if the soft keyboard is displayed the Toast sort of merged with the soft keyboard and is hard to distinguish. So I looked up how to set a custom view to a Toast. But the View property (SetView and GetView methods) is deprecated.
Instead I was told to use a Snackbar.
I have managed to create a Snackbar with a custom view. I have these problems:
The Snackbar's position is in the lower left corner of my app.
I would like to display the Snackbar as a Toast is displayed:
At the bottom and in the middle of the screen.
Some distance between the Snackbar's bottom and the screen's bottom.
The Snackbar is displayed behind the soft keyboard.
I would like to display the Snackbar above the soft keyboard.
I can hide the soft keyboard to show the Snackbar. But I would prefer not to hide it.
I have googled a lot on these two problems, but have not found any solutions.
For problem #1 I have tried
How can you adjust Android SnackBar to a specific position on screen
I was not able to get the CoordinatorLayout to compile.
Setting the margin on a Layout didn't work.
For problem #2 I have tried
Show Android SnackBar above keyboard? but it didn't work.
Here is my code:
res/layout/snackbar.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView style="#style/SomeStyle"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/tvSnackbarText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Snackbar" />
Fragment
private fun showSnackbarMessage(message: String) {
val view: View = LayoutInflater
.from(context)
.inflate(R.layout.snackbar, null)
val tvSnackbarText = view.findViewById<TextView>(R.id.tvSnackbarText)
tvSnackbarText.text = message
tvSnackbarText.gravity = Gravity.CENTER
val snackbar = Snackbar.make(requireView(), "", Snackbar.LENGTH_LONG)
snackbar.view.setBackgroundResource(R.drawable.rounded_corner_box_grey_stroke);
val params = snackbar.view.layoutParams as FrameLayout.LayoutParams
params.height = FrameLayout.LayoutParams.WRAP_CONTENT
params.width = FrameLayout.LayoutParams.WRAP_CONTENT
snackbar.view.layoutParams = params
val layout = snackbar.view as Snackbar.SnackbarLayout
layout.addView(view)
snackbar.show()
}
Related
Is there any way that I can position my Toast message in the center of the screen? Since Toast.setGravity() is not supported for Android 11 and above devices(API level 30 and above) as per android official documentation. I am not able to position my toast in the center of the screen. I searched all over for the solution but had no luck. My requirement is, I want to display a message similar to toast to be displayed at the center of the screen. I used a snack bar, but that is not what I am expecting. It is not necessary for me to display toast. I just want something to mimic the same functionality as that of a toast i.e. display a feedback message at the center of the screen.
Thank you.
The restriction on setting gravity for Toasts applies only to text toasts (created using the Toast.makeText(...) method). You can create a regular toast (by calling standard constructor - Toast(activity)), set gravity and customize it by setting a custom view.
As a result, you get something like this:
val customToast = Toast(this).also {
// View and duration has to be set
val view = LayoutInflater.from(context).inflate(R.layout.foo_custom_toast, null)
it.setView(view)
it.duration = Toast.LENGTH_LONG
it.setGravity(Gravity.CENTER, 0, 0)
}
Also, you can check this question and this article, I think this will help you.
P.s If you only need to show the text in your toast then in the Toast's custom view add a textView and then, when setting up the toast (setting the custom view) set the text to this textView. Also, through customView, you can customize Toast as you like.
Here's how to do it with a Snackbar, provided you have a screen-sized ConstraintLayout in your hierarchy.
In your main Activity's ConstraintLayout, add a horizontal guideline at the center of the screen:
<androidx.constraintlayout.widget.Guideline
android:id="#+id/centerHorizontalGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".50" />
Then in your Activity, you can set the anchor view of the Snackbar to this Guideline. Setting an anchor view tells it where to appear on the screen, instead of the default of the bottom.
fun showCenteredSnackbar(#StringRes messageId: Int, duration: Int = Snackbar.LENGTH_SHORT) {
Snackbar.make(this, binding.container, getText(messageId), duration)
.setAnchorView(binding.centerHorizontalGuideline)
.show()
}
where binding.container is the ConstraintLayout.
Your fragments can call this function using (requireActivity() as MainActivity).showCenteredSnackbar().
I have countered a situation that needs to implement a scrollable modal bottom sheet. Basically, it will show half off the screen at first, then when scrolling up, it will stretch to 90% of the screen. If keep swiping up, it will scroll the content inside bottom sheet.
What I have tried
layout.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/design_bottom_sheet"
style="#style/RootLayout"
android:background="#drawable/rounded_shape"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<...Content.../>
</android.core.widget.NestedScrollView>
</FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
Bottom Sheet Dialog class
I followed the answer here accepted answer
Result
It only shows half of the screen when opened, and not scroll the bottom sheet to Expanded State when I scroll the contents up like this result.
Expectation
I expected the above code should behave like this expectation
Does any one have the solution for this situation?
Thank you
So after more than a week, I found a solution for this problem,
I override the onCreateDialog method like below
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// This will disable the behavior of bottom sheet to have a flat corner
//https://github.com/material-components/material-components-android/pull/437#issuecomment-678742683
val dialog = BottomSheetDialog(requireContext(), theme)
dialog.behavior.disableShapeAnimations()
dialog.setOnShowListener { dialogInterface ->
val bottomSheetDialog = dialogInterface as BottomSheetDialog
val parentLayout =
bottomSheetDialog.findViewById<View>(com.google.android.material.R.id.design_bottom_sheet)
parentLayout?.let { it1 ->
val behaviour = BottomSheetBehavior.from(it1)
it1.layoutParams.also {
it.height =
context?.resources?.displayMetrics?.heightPixels?.times(0.9)?.toInt()!!
}
behaviour.peekHeight =
context?.resources?.displayMetrics?.heightPixels?.times(0.6)?.toInt()!!
}
}
return dialog
}
What is happening in this code?
I was NOT use the dialog provider by BottomSheetDialog neither super.onCreateDialog()
Instead I used BottomSheetDialog(context,theme) in order to create my custom bottom sheet theme.
Then, I set listener for dialog, get parent layout and bottom sheet dialog like below. The most important part is dealing with behavior.
After achieved the behavior correctly, you are done. Setting it's state to be expanded as recommended by #Nitish Chaudhary and setting the layout height to the height that you want. That's all I need, also this code below is reusable to me wherever you follow the modal bottom sheet XML layout rule.
Happy coding.
Is there any way i can design a bottom sheet fragment as follows:
I need to set the width of the bottom sheet to 1/4 of the screen. IS it possible to implement this?
Thanks for your help.
You can achieve the same result with this library. Or just make the same CornerSheetBehavior. As you can see it's just a BottomSheetBehavior with managing of translationX of view
Create a layout file for your bottom sheet as normal, and set the width to what you need:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/sheet_background"
android:layout_width="100dp"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="100dp"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
app:behavior_peekHeight="150dp"
android:id="#+id/drag_up_from_here">
<!-- Bottom sheet contents here -->
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Then to get it to stick to the right hand side, you can programmatically append the bottom sheet to your layout. This is how I add my bottom sheets:
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
val bottomSheet = inflater.inflate(R.layout.bottomsheet_layout, null)
val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet.findViewById<View>(R.id.drag_up_from_here)
// Allow user to drag part of bottom sheet
bottomSheet.findViewById<LinearLayout>(R.id.drag_up_from_here).setOnClickListener {
if (bottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED)
} else {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
}
}
// Create popup window
val bottomSheetPopup = PopupWindow(popupViewLower,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT,
false)
// Get the view you want the bottom sheet added to
val currentView = findViewById<ConstraintLayout>(R.id.main_view)
// Display the popup window
bottomSheetPopup.showAtLocation(currentView, Gravity.BOTTOM, currentView.measuredWidth, 0)
The key for getting it on the right of the screen is this part:
bottomSheetPopup.showAtLocation(currentView, Gravity.BOTTOM, currentView.measuredWidth, 0)
Where currentView.measueredWidth is passed as the x value, moving the bottom sheet all the way to the right.
Edit: I realized you're also asking for the width to be exactly 1/4 the width of the screen. To do this, programmatically set the width of the bottom sheet layout to currentView.measuredWidth / 4. This post explains this well: Android view layout_width - how to change programmatically?
I am able to open my BottomSheetDialogFragment with
val bottomSheet = BottomSheetFragment()
bottomSheet.show(fragmentManager!!, "BottomSheet")
but it only opens to show half of its content - I would like it to expand on opening to the full height of the screen without having to drag it up.
I have looked around and it seems one way is to set the BottomSheetBehavior state to STATE_EXPANDED, but I have not been able to find a solution on how to do this in Kotlin.
Any help would be appreciated!
You can set the BottomSheetBehavior state by placing this inside
onViewCreated of your BottomSheetDialogFragment.
dialog.setOnShowListener { dialog ->
val d = dialog as BottomSheetDialog
val bottomSheet = d.findViewById<View>(R.id.design_bottom_sheet) as FrameLayout
val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}
You may also want to set the peek height to the height of your dialog to prevent the dialog getting stuck half way when attempting to dismiss it.
bottomSheetBehavior.peekHeight = bottomSheet.height
I'm seeing a problem where the snackbar expands itself to fit the size of a listview on the screen when the soft keyboard is up.
Snackbar with issue
Normal snackbar (keyboard not up)
I've been able to slightly remedy this by setting the height programatically, however then the text disappears from the snackbar and I have no idea how to add it back.
ViewGroup.LayoutParams lp = snackbarView.getLayoutParams();
lp.height = 150;
snackbarView.setLayoutParams(lp);
The snackbar is added as follows:
mConnectionLostSnackbar = Snackbar.make(view, mConnectionLostString, Snackbar.LENGTH_INDEFINITE);
final View snackbarView = mConnectionLostSnackbar.getView();
TextView textView = snackbarView.findViewById(android.support.design.R.id.snackbar_text);
textView.setLineSpacing(0, SNACKBAR_LINE_SPACING_MULTIPLIER);
snackbarView.getViewTreeObserver().addOnPreDrawListener(new NotDismissiblePreDrawListener(snackbarView));
mConnectionLostSnackbar.show();
I would appreciate any thoughts on not having the snackbar expand when the keyboard is up. Thanks in advance.
I have noticed that this only happens when the Snackbar is attached to a CoordinatorLayout that has ANOTHER CoordinatorLayout parent somewhere up the hierarchy. I guess the behaviour of <add as much bottom padding as needed to display the Snackbar above the keyboard> gets duplicated because of the multiple CoordinatorLayouts, and the Snackbar ends up taking the entire screen.
The solution is to attach the Snackbar to the topmost CoordinatorLayout. In my scenario I have an Activity with a CoordinatorLayout content view, that hosts a fragment that has a CoordinatorLayout as the root view. When the fragment needs to display a Snackbar, it attaches it to the Activity's CoordinatorLayout, and then it behaves correctly when the keyboard is displayed. Note that I am now using the AndroidX library instead of the support library, so the behaviour may be slightly different.
The same happened to me, but I could not find the reason of the problem.
To avoid expanding the snackbar, I decided keep it behind the keyboard. This was achieved by adding this line to the desired activity on the manifest
android:windowSoftInputMode="adjustNothing"
I would really like to know why it happens, because on this project I use snackbar a lot and it only breaks on one activity
Just put this property in your Manifest file to your proper activity.
<activity android:name=".YourActivity"
android:windowSoftInputMode="adjustResize"/>