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?
Related
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()
}
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.
We are creating a View programmatically in onCreate method and trying to set either of the following to that view-
The top and left or
The bottom and right.
But it's not working. These absolute positions can be relative to the screen or to the parent layout. Here is an example to reproduce the same thing-
main.xml.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="#+id/root"
android:layout_height="match_parent">
</RelativeLayout>
And here is the MainActivity, where I am trying view programmatically.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
val root = findViewById<RelativeLayout>(R.id.root)
val layoutParams = RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
)
val view = TextView(this)
view.layoutParams = layoutParams
view.text = "Test View"
//Applying top and left value in pixels.
view.top = 100
view.left = 100
root.addView(view)
}
}
top and left values are not getting assign to the view.
We have tried with many other layouts-
FrameLayout
LinearLayout
AbsoluteLayout (deprecated so not considering)
We have also tried to use View#layout() method but it didn't work either.
We have referred to the following articles-
How can I dynamically set the position of view in Android?
Usage of forceLayout(), requestLayout() and invalidate()
Android set view position - setY vs setTop
https://www.tutorialspoint.com/how-to-set-the-absolute-position-of-a-view-in-android
https://mindmajix.com/android/absolute-layout
https://developer.android.com/guide/topics/ui/how-android-draws.html
Android: addView and layout method does not work together
Android-layout does not work properly
Android Studio does not show layout preview
Set the absolute position of a view
https://www.tabnine.com/code/java/methods/android.view.View/setBottom
I'have created the splash screen without any layout xml file but this is done by the vector drawable with centring the app logo like below:
<item name="android:windowBackground">#drawable/splash_background</item>
But I also would like to show the same app logo in the next subsequent screen. For e.q. In my case let us say Main Activity screen where I've a layout xml where I've centred the icon with the constraint layout.
activity_main.xml
<!-- By adding android:layout_marginTop="26dp" to the ImageView kind of works but not sure why the magic number works
Not sure where to get the same number for some other devices-->
<ImageView
android:id="#+id/imageViewLogo"
android:layout_width="#dimen/splash_icon"
android:layout_height="#dimen/splash_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_invest_logo" />
</android.support.constraint.ConstraintLayout>
But I noticed when the same asset logo swap happens between Splash and Main Activity I can see a jumpy behaviour with the logos.
Appreciate your help. Below is the github for the entire source code.
https://github.com/nksaroj/InvestApp
You can see the jumpy issue with the green logo here
getWindow().getDecorView().getRootView().getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Layout has happened here.
float statusBarHeight = getStatusBarHeight() * 1f;
//This is tricks where Samsung and some other devices don't consider the height in splash screen so that you need to adjust the height manually
View navigationBarBackground = findViewById(android.R.id.navigationBarBackground);
if (navigationBarBackground == null) {
statusBarHeight = statusBarHeight * -1f;
}
imageViewIconY = imageViewReadyIcon.getY() + (statusBarHeight / 2);
imageViewIconY.setY(imageViewIconY);
// Don't forget to remove your listener when you are done with it.
getWindow().getDecorView().getRootView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
I have an app where an image is loaded and attached to Chris Banes PhotoView. When I click the image it goes to a layout and creates a fullscreen layout, this is needed to hide other functionality on the layout where the image is.
The imageView is set to match_parent on width and height because if it is set to match_content you can't really pinch to zoom. Because of this there is a lot of room around the picture, which is a transparent imageView which is used when a user uses pinch to zoom in.
The problem lies in the expected behavior that if you click on the transparent part next to the image that the fullscreen layout closes. However that is the same imageView that the image needs to expand in.
Initially I searched and found
dialog.setCanceledOnTouchOutside(true);
But because the imageView takes up the whole screen so the image can expand into it there really is no outside to touch.
Is there an easy solution here? Like initially having the imageView set to match_content but when you start zooming that it sets the new width/height to what it needs? Or is it possible to address that extra space that isn't used by the imageView and set a dialog.dismiss or something on that.
Or is it just not possible in my current setup.
xml code (there is more but that isn't relevant for my question)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#android:color/transparent"
android:orientation="vertical">
<ImageView
android:id="#+id/iv_map_full_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/ll_container_close_button"
/>
</RelativeLayout>
Code from fragment
private void showDialogFullscreenMap() {
final Dialog alertDialog = new Dialog(getActivity());
alertDialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
alertDialog.setCanceledOnTouchOutside(true);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View convertView = inflater.inflate(R.layout.dialog_map_fullscreen, null, false);
ImageView ivFullScreen = (ImageView) convertView.findViewById(R.id.iv_map_full_screen);
ivFullScreen.setImageBitmap(mTempBitmap);
mAttacher = new PhotoViewAttacher(ivFullScreen);