I have a ListView shown in the screen and there is a Snackbar which is shown indefinitely. The last element of the ListView is getting covered partially because of the Snackbar.
I am trying to get the height of the Snackbar and give it as a bottom margin programmatically to the ListView.
Snackbar snackbar =
Snackbar.Make(_refresher,"message",Snackbar.LengthIndefinite);
snackbar.Show();
View snackbarView = (Snackbar.SnackbarLayout)snackbar.View;
int h = snackbarView.MeasuredHeightAndState;
But the height of the Snackbar is always 0.
I also tried snackbarView.Height and snackbarView.MinimumHeight, but it always returns 0.
Can anybody help me solving this issue?
i am not familiar with xamarin but i work with snakbar many times so may this work like this
You need to use view.post because height property only becomes available after the view is inflated/run
Ref : https://developer.xamarin.com/api/type/Android.Views.View/
Ref : https://developer.xamarin.com/api/type/Java.Lang.IRunnable/
snackbar.View.Post(() =>
{
int h=snackbar.View.Height();
Log.Error ("Height", "Height"+h);
});
i hope it helps
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'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"/>
What I intend to achieve
The item view should occupy the entire height of the item
It could be that the item height is lesser than the height of the tallest item in the recyclerview, in which case it should just stick to the top like in the screenshot above.
The bug I'm running into
As in the screenshot above, views are getting truncated.
What I've tried so far
Initially I went with wrap_content on the recyclerview, now that it is supported. It didn't work when none of the views visible on the screen at the time were the tallest. This makes sense in how the view hierarchy is laid out. How can the height of something which hasn't even been bound to any data yet be calculated if the height is dependent on that data?
Workaround time :S
Instead of trying a custom layoutmanager, I first went with what I felt needed to be done - laying out all item views at the beginning to figure out their height.
There's a progressbar and an animation playing in the upper part of the screen to catch the user's attention while all this happens with recyclerview visibility set to invisible. I use two things, one didn't suffice - I've attached an observer in the adapter's onViewAttached() call and I've used a scroll change listener as well. There's a LinearSnapHelper attached to the recycler view to snap to adjacent (next or previous, depending on the scroll direction) position on scroll.
In this setup,
I'm going to each position in the recyclerview using layoutManager.smoothScrollToPosition()
Getting the child view height using
View currentChildView = binding.nextRv.getChildAt(layoutManager.findFirstCompletelyVisibleItemPosition());
if (currentChildView != null) {
currentChildHeight = currentChildView.getHeight();
}
in scroll change listener on RecyclerView.SCROLL_STATE_IDLE or by passing the height to the view attached observer mentioned above in the adapter's onViewAttachedToWindow()
#Override
public void onViewAttachedToWindow(BindingViewHolder holder) {
if (mObserver != null) {
mObserver.onViewAttached(holder.binding.getRoot().getHeight());
}
}
Storing a maxHeight that changes to the max of maxHeight and new child's height.
As is evident, this is ugly. Plus it doesn't give me the current view's height - onAttached means it's only just attached, not measured and laid out. It is the recycled view, not the view bound to current data item. Which presents problems like the truncation of view illustrated above.
I've also tried wrap_content height on the recycler view and invalidating from recycler's parent till the recycler and the child on scroll coming to SCROLL_STATE_IDLE. Doesn't work.
I'm not sure how a custom layoutmanager can help here.
Can someone guide me in the right direction?
I could not accept #Pradeep Kumar Kushwaha's answer because against one solution, I do not want different font sizes in the list. Consistency is a key element in design. Second alternative he gave couldn't work because with ellipsize I would need to give a "more" button of some sort for user to read the entire content and my text view is already taking a click action. Putting more some place else would again not be good design.
Changing the design with the simple compromise of resizing the recyclerview when the tallest, truncated item comes into focus, it turns into the simple use case of notifyItemChanged(). Even for the attempt I made using the view attached observer and scroll state listener, notifyItemChanged could be used but that approach is just too hacky. This I can live with in both code and design. Here goes the code required.
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
int position = ((LinearLayoutManager) binding.nextRv.getLayoutManager())
.findFirstVisibleItemPosition();
if (position != nextSnippetAdapter.getItemCount() - 1) {
binding.nextRv.getAdapter().notifyItemRangeChanged(position, 2);
} else {
binding.nextRv.getAdapter().notifyItemChanged(position);
}
}
}
For my particular setup, calling for just these two elements works. It can further be optimized so as to call for single element at position + 1 in most cases, and checking and calling for the appropriate one in corner (literal) cases.
Inside your adapter where I can find two cards one on top and another on bottom
How I would have defined my layout is like this:
Cardview1
LinearLayout1 --> orientation vertical
cardview2 (Top card where text is written)
Linearlayout2 (where I can see icons such as like etc)-->orientation horizontal
Now fix the height of Linearlayout2 by setting it to wrap content.
And the height of cardview2 should be 0dp and add weight = 1
Now inside cardview2 add a TextView1 to matchparent in height and width.
Better inside textview1 add ellipsize to end and add max lines
If you want to show all lines try to find autoresizetextview library it can be founded here --> AutoResizeTextView
Hope it helps.
I think the recyclerview can be set to height wrap_content. And the items can be make like height to match_parent.
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layput_height="wrap_content"/>
Item as:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
// your coode
</androidx.constraintlayout.widget.ConstraintLayout>
I had little more requirement than the question. Even my problem solved in the way.
Remember I am using:
androidx.recyclerview:recyclerview:1.0.0-beta01
dependency for the project
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());
I have this issue where I have a relative layout that has two child relative layouts (leftpanel and rightpanel). They're inside a custom layout for listview items and each item is updated from a json response from the server. So the size depends on what the server provides.
Issue: I want to have each panel's height to match each other, but it seems that setting layout_height to match_parent doesn't work (actually, if this can be resolved, then no more problems).
What I did: I programmatically set the align top and bottom of each panel to each other -- if the other's bigger, adjust the other one and vice versa. So what I did was to have a view (rightpanel) to listen to rightPanel.getViewTreeObserver().addOnScrollChangedListener(), and call the method below everytime there's a scroll change:
private void updateLayoutAlignmentParams(ViewHolder viewHolder) {
RelativeLayout.LayoutParams leftPanelLayoutParams = (RelativeLayout.LayoutParams)viewHolder.leftPanel.getLayoutParams();
RelativeLayout.LayoutParams rightPanelLayoutParams = (RelativeLayout.LayoutParams)viewHolder.rightPanel.getLayoutParams();
int leftPanelHeight = viewHolder.leftPanel.getHeight();
int rightPanelHeight = viewHolder.rightPanel.getHeight();
if(leftPanelHeight > rightPanelHeight) {
rightPanelLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, 0);
rightPanelLayoutParams.addRule(RelativeLayout.ALIGN_TOP, 0);
leftPanelLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, viewHolder.rightPanel.getId());
leftPanelLayoutParams.addRule(RelativeLayout.ALIGN_TOP, viewHolder.rightPanel.getId());
} else {
leftPanelLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, 0);
leftPanelLayoutParams.addRule(RelativeLayout.ALIGN_TOP, 0);
rightPanelLayoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, viewHolder.leftPanel.getId());
rightPanelLayoutParams.addRule(RelativeLayout.ALIGN_TOP, viewHolder.leftPanel.getId());
}
}
What happens: not all the views get updated while scrolling; so I get a lop-sided listview item where one is bigger than the other vertically but some do adjust well. Odd thing is, when the item gets out of view, it's lop-sided, then gets corrected consistently.
Note: I also tried
addOnDrawListener() - every item is updated but I get an ArrayList out of bounds index but doesn't point to any line in my code. Wouldn't be the best solution anyway as I need to support devices with API < 16.
setOnGlobalLayoutListener() - Nothing happens.
Please let me know if you know why or have a better solution.
Finally [kindof] fixed it! Replaced the whole method with the code below:
private void updateLayoutAlignmentParams(ViewHolder viewHolder) {
viewHolder.rightPanel.setMinimumHeight(viewHolder.leftPanel.getHeight());
viewHolder.leftPanel.setMinimumHeight(viewHolder.rightPanel.getHeight());
}
Although, I was able to achieve having the left and right panel aligned with each other using the code above. I'm now having issues where the previous view's height and width are retained when I switch views. :(
Edit:
Okay, I ended up using LinearLayout to wrap the whole listview item. Not really sure why RelativeLayout isn't complying with match_parent, though.