How can you adjust Android SnackBar to a specific position on screen - android

Follwing the new android snackbar, i'm trying to set it to be positioned on a specific y coordinate. Its seems to be not even a possible.
I've tried with getting the parent of the snackbar's view, but, there's nothing to be done to the parent for it to set the position of it.
mSnackBar.getView().getParent();
When digging into the actual class, there's an instance of mView, and mParent which is private, and can't be reached anyhow.
https://developer.android.com/reference/android/support/design/widget/Snackbar.html

It is possible to set the location that the Snackbar is displayed by positioning a android.support.design.widget.CoordinatorLayout within your existing Activity layout.
For example, say your existing layout is a RelativeLayout you could add a CoordinatorLayout as follows:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="#+id/myCoordinatorLayout"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
</android.support.design.widget.CoordinatorLayout>
Then, make sure you pass the CoordinatorLayout as the first argument of the Snackbar.make() command.
final View viewPos = findViewById(R.id.myCoordinatorLayout);
Snackbar.make(viewPos, R.string.snackbar_text, Snackbar.LENGTH_LONG)
.setAction(R.string.snackbar_action_undo, showListener)
.show();
This will result in the Snackbar being shown at the bottom of the CoordinatorLayout provided to the make() function.
If you pass a View that is not a CoordinatorLayout the Snackbar will walk up the tree until it finds a CoordinatorLayout or the root of the layout.

Defining a layout explicitly for the Snackbar may not always be practical.
The issue seems to have been targeting the parent, rather than the Snackbar.
Snackbar snackbar = Snackbar.make(layout, message, duration);
View snackbarLayout = snackbar.getView();
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
// Layout must match parent layout type
lp.setMargins(50, 0, 0, 0);
// Margins relative to the parent view.
// This would be 50 from the top left.
snackbarLayout.setLayoutParams(lp);
snackbar.show();

I have an interesting idea for you.
You can just use the code below to get where you want.
Snackbar.make(View,Message , Snackbar.LENGTH_LONG)
.setAnchorView(pb)
.show();
Here setAnchorView is used to change the postion. You can create your layout in the xml file. Just call your layout inside the setAnchorView and it will show on the position of the xml layout.

You can use setAnchorView (#IdRes int anchorViewId) method of a snackbar to set it above anchor view
https://developer.android.com/reference/com/google/android/material/snackbar/Snackbar#make(android.view.View,%20java.lang.CharSequence,%20int)

In addition to brentm's answer, I had to use:
androidx.constraintlayout.widget.ConstraintLayout
and add the dependency for it:
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"

Related

Is there any alternative for Toast.setGravity() to support in android 11 and above devices?

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().

Snackbar expands when soft keyboard is showing

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"/>

Snackbar is not dismissing on swipe

i have a snackbar in my appcompat activity. It has a button OK which dismiss the snackbar.It is working perfact. but i can't dismiss the snackbar on swipe(left to right).
Following is my code for snackbar....
final Snackbar snackbar = Snackbar
.make(view, "Error Message", Snackbar.LENGTH_INDEFINITE);
snackbar.setAction("OK", new View.OnClickListener() {
#Override
public void onClick(View view) {
snackbar.dismiss();
}
});
snackbar.show();
Edit 1
I have Relative layout as parent layout in my activity's XML layout.
Snackbar needs a CoordinatorLayout as its root layout or some where on top of it, to perform its various operations like swipe to dismiss. You need to have that some where in your layout hierarchy.
Further the view that we pass in the Snackbar.make() method is used to search a CoordinatorLayout some where in the view hierarchy. The method traverse from this view to the root view to find a CoordinatorLayout over which it can show the snackbar and perform its animations and operations.
So try replacing root layout to CoordinatorLayout and your problem will be solved.
As a reference to Ashwani Kumars answer.
I saw Intimate asked if there is a way to implement this with LinearLayout. Well simple wrap your original LinearLayout with a CoordinatorLayout with
match_parent in android:layout_height and android:layout_width attributes.
this will keep your original arrangement and still make sure the Snackbar is swipable.
Snackbar will now look like this:
For fragments -
Snackbar.make(getView(), "Error Message", Snackbar.LENGTH_INDEFINITE);
For activities -
Snackbar.make(this.findViewById(android.R.id.content), "Error Message", Snackbar.LENGTH_INDEFINITE);
Assuming you wraped your whole layout with CoordinatorLayout and this is the root layout.
I've written a library that supports swipe to dimiss behaviour even without providing CoordinatorLayout. Users can swipe both left or right to dismiss it (you can only swipe to right originally). It also includes progressBar and other stuff. Try it out https://github.com/tingyik90/snackprogressbar.
All you need to do is to create a SnackProgressBar and allow swipe to dismiss. Sample code:
SnackProgressBar messageType = new SnackProgressBar(
SnackProgressBar.TYPE_MESSAGE, "Your message")
.setSwipeToDismiss(true)
Snackbars in my GLSurfaceView game don't dismiss with a swipe, and users may not know to swipe anyway if they did. The following one line of code dismisses a Snackbar with any touch of the bar. Critically I found if the user does happen to hit the action button if it has one, whatever action it is set to do is still performed. The overall dismiss does not get in the way.
snackbar.getView().setOnClickListener(view -> snackbar.dismiss());

Configure CoordinatorLayout from code

I'm dynamically injecting a content view into the CoordinatorLayout and would now like to apply a layout_below property to the injected view so that it isn't hidden behind the AppBar.
Is there any way to do this at runtime from code instead of xml properties of the annotation?
Taking one step back and building the entire view in plain xml, I realized that layout_below is not the property I needed for my use case: placing the content view below the app bar. I did not make this clear in my question though, as I assumed layout_below would be the proper option for that.
In fact, to insert a non scrolling view into the CoordinatorLayout it should first be wrapped with a android.support.v4.widget.NestedScrollView. Then, to avoid its content being hidden behind the app bar, it is necessary to update its behavior to android.support.design.widget.AppBarLayout.ScrollingViewBehavior. Otherwise a default behavior is used which will hide behind the app bar.
val viewToInsert = getLayoutInflater.inflate( id, coordinatorWrapper, false )
val p = viewToInsert.getLayoutParams.asInstanceOf[Coordinator.LayoutParams]
p.setBehavior( new ScrollingViewBehavior )
coordinatorWrapper.addView( viewToInsert, 1, p )
You could try setting an anchor.
ContentView view = getContentView(); //your view
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
params.setAnchorId(R.id.app_bar_layout);
params.anchorGravity = Gravity.BOTTOM; //we will anchor to the bottom line of the appbar
params.gravity = Gravity.BOTTOM; //we want to be BELOW that line
view.setLayoutParams(params);

Show custom view in all activities

I want to show a view that should be shown in all activities. I don't know how to inherit views in android. What i did is below, its showing the view in first activity but not in all activities. This pease of code is form my BaseActivity, please help
LayoutInflater inflater = getLayoutInflater();
View child = inflater.inflate(R.layout.custom_error, null);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( LayoutParams.WRAP_CONTENT , LayoutParams.WRAP_CONTENT );
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
addContentView(child, params);
You could get an Android specific View in the Activity. For example the following code below will add a TextView to the Activity's content area.
TextView tvSample = new TextView(this);
tvSample.setText("Hello!");
((ViewGroup) hostActivity.findViewById(android.R.id.content)).addView(this);
Whereby hostActivity is your current Activity and android.R.id.content is a specific element (the content area, not including the ActionBar).
Alternatively, as already stated, make use of <merge> and <include> tags in your layout XMLs.
you can do this with two solution
for programmatically
1)After adding child view to you parent View need to call setContentView(parentView) and pass you parent layout to it.
and With XMl
2) You can use include tag. follow this link will help you.
http://developer.android.com/training/improving-layouts/reusing-layouts.html
Have you tried 'include' tag of xml? It will do the job.
<include
android:id="#+id/container_header_lyt"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_above=...
android:layout_toLeftOf=...
layout="#layout/header_logo_lyt" //Name of the xml layout file you want to include
/>
In the layout/xxxx use the name of your layout file that should be repeated.
After use the above code in your xml file like any other widget.
When you want to show it:
FrameLayout rootLayout = (FrameLayout)findViewById(android.R.id.content);
View.inflate(this, R.layout.overlay_layout, rootLayout);
Then when you want to remove it:
FrameLayout rootLayout = (FrameLayout)findViewById(android.R.id.content);
rootLayout.removeViewAt(rootLayout.getChildCount()-1);
That's a concise solution, you should remove the View by giving the RelativeLayout an id in the XML file, then remove by: rootLayout.removeView(findViewById(R.id.the_id_of_the_relative_layout));.
Answer by nmw

Categories

Resources