My app contain a bottomsheeet and i am using following methods to change its state
public void toggleBottomSheet() {
if (sheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
} else {
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
But in some devices it is not showing animation properly ( Bottom to up ), It opens directly like popup.
How to add animation so it looks it is coming from bottom.
Not sure about this point of "in some devices", can you please mention the android version and other specifications? My suggestion is to add a BottomSheetBehavior.BottomSheetCallback to the BottomSheetBehavior
and in its onSlide method put a log.d() to check if its really sliding. It will help to find out the cause. Also, make sure that you have added the right BootmSheetBehavior and you can try by setting the peeckHeight explicitly.
yourBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback()
{
#Override
public void onStateChanged(#NonNull View view, int newState)
{
if (newState == BottomSheetBehavior.STATE_EXPANDED)
{
}
}
#Override
public void onSlide(#NonNull View view, float v)
{
Log.d("tag", "sliding from bottom to top");
}
});
Related
I have a problem where in a specific situation when I call setVisibility(GONE) inside my custom view, its onVisibilityChanged method doesn't get called and it actually doesn't hide the view although getVisibility() returns 8 (or GONE) afterwards.
Here is how I know the visibility changes but onVisibilityChanged is not called.
#Override
protected void onVisibilityChanged(#NonNull View changedView, int visibility) {
Log.i(LOG_TAG, "onVisibilityChanged: " + visibility);
super.onVisibilityChanged(changedView, visibility);
}
#Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
Log.i(LOG_TAG, "setVisibility: " + visibility);
}
public void hide(){
Log.i(LOG_TAG, "before hide visibility: " + getVisibility());
setVisibility(GONE);
Log.i(LOG_TAG, "after hide visibility: " + getVisibility());
}
Normally when I call hide() I see these lines in the log:
before hide visibility: 0
onVisibilityChanged: 8
setVisibility: 8
after hide visibility: 8
But in a spicific situation when I call hide() I get these lines in the log and the view isn't hidden afterwards although getVisibility() returns 8:
before hide visibility: 0
setVisibility: 8
after hide visibility: 8
So when in general does this happen? When does setVisibility not call onVisibilityChanged?
Don't ask what my specific situation is. But please provide every general situation where this might happen.
It is called only when the view is attached in the hierarchy.
The call to setVisibility looks like this:
public void setVisibility(#Visibility int visibility) {
setFlags(visibility, VISIBILITY_MASK);
}
The setFlags method is a long one where a bunch of different view properties are changed and handled, but the noticable part is this:
if ((changed & VISIBILITY_MASK) != 0) {
// if visiblity changed...
...
if (mAttachInfo != null) { // true if attached in view hierarchy
dispatchVisibilityChanged(this, newVisibility); // onVisibilityChanged is called from here
...
So you will see your described behaviour on a view that's not attached to a fragment or activity.
you can use another way to solve this problem
create a method like this
private void stateCheck(View view){
if (view.getVisibility()==View.GONE){
// handle gone state
}else if (view.getVisibility()==View.INVISIBLE){
// handle invisible state
}else{
// handle other states
}
}
View.onVisibilityChanged
Called when the visibility of the view or an ancestor of the view has
changed.
As this says, onVisibilityChanged will only be called when visibility is changed.
public void hide(){
setVisibility(GONE);
}
This will be called in two cases.
When visibility is VISIBLE.
When visibility is INVISIBLE.
This will not be called if View visibility is already set to GONE.
Solution
So how can you capture all the events of visibility?
Override setVisibility method in your custom view class. This method will be called every time visibility is called. Like below
public class CustomTextView extends AppCompatTextView {
#Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
System.out.println("CustomTextView.setVisibility " + visibility);
}
}
Update
I could not get this situation. But here is a workaround for getting rid of your problem.
If you are sure, that your code either calls onVisibilityChanged or setVisibility when visibility is changed. Then you can do this.
customTextView.setOnVisibilityChange(new CustomTextView.OnVisibilityChange() {
#Override
public void onVisibilityChange(int visibility) {
}
});
Here is the sample view class.
public class CustomTextView extends AppCompatTextView {
private int currentVisibility = 0;
OnVisibilityChange onVisibilityChange;
public void setOnVisibilityChange(OnVisibilityChange onVisibilityChange) {
this.onVisibilityChange = onVisibilityChange;
}
#Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
callback(visibility);
}
#Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
callback(visibility);
}
private void callback(int visibility) {
if (currentVisibility != visibility && onVisibilityChange != null)
onVisibilityChange.onVisibilityChange(visibility);
currentVisibility = visibility;
}
public interface OnVisibilityChange {
void onVisibilityChange(int visibility);
}
}
I have a Recyclerview, im animating a view inside individual list item, but when I scroll the recyclerview the animation is stopping. Its because recyclerview removes the items form its view so when we scroll back it fetches it back! But now i want that animation to keep going as I would stop it only when i get data from server!
All I want is the animation that I start in the individual items inside the recylerview shouldn't stop even if the recyclerview is scrolled and the view is out of focus and comes back to focus! I need to stop the animation in the code when I get the server data! I have the code where to stop the animation and it works if the item is not scrolled off the view!
btn.onClick -- this button is the onClick for the recyclerview list
item 1 btn.startAnimation(anim.xml) -- starting the animation
onSuccess -- server returns success btn.clearAnimation();
but before the onSuccess if we scroll the list the animation is stopped!
Please help!
By inspiring from crymson's answer i have made little easy and useful solution using tag method of View instead setting a boolean in complicated logic of your custom adapter.
#Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (holder.getItemViewType() == TYPE_AD)
((ViewHolderForAd) holder).ivStory.setTag(false);
}
public class ViewHolderForAd extends RecyclerView.ViewHolder {
private ImageView ivStory;
TextView tvName;
public ViewHolderForAd(View view) {
super(view);
ivStory = (ImageView) view.findViewById(R.id.ivStoryImage);
tvName = (TextView) view.findViewById(R.id.tvAppName);
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int pos = getAdapterPosition();
if (pos < 0) {
pos = (int) v.getTag();
}
customItemClickListener.onItemClicked(v, pos);
}
});
//ivStory.startAnimation(AnimationUtils.loadAnimation(context, R.anim.pulse_story));
ivStory.setTag(false); //Set default tag false to decrease risk of null
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
//...Your code...
if (!(boolean) holder1.ivStory.getTag()) {
holder1.ivStory.setTag(true);
holder1.ivStory.startAnimation(AnimationUtils.loadAnimation(context, R.anim.pulse_story));
}
//...Your code...//
}
You can use setTag(key, object) instead of setTag(object) if you already tagged something(like position) in your imageView.
Hope this helps someone.
Hard to give you a full solution but have you tried saving the animation state inside the ViewHolder that you are using? I'd recommend saving a boolean flag in the ViewHolder class you defined like isAnimating which is initially set to false and in your onBindViewHolder(...) method you can do something like
if (viewHolder.isAnimating) {
// start animation
} else {
// clear animation
}
viewHolder.btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.isAnimating = true;
// start animation
}
});
I am using swipelayout from daimajia.I get some data from services.When the service has a date than will visible an icon that will open the left sideBut it do nothing when clicking the icon.I have no error that's the reason why cannot resolve it.The action is when clicking the icon,that visible a textview and start a chronometer.
Here is my swipeListener
private SwipeListener swipeListener = new SwipeListener() {
#Override
public void onStartOpen(SwipeLayout layout, SwipeLayout.DragEdge edge) {
if (edge == SwipeLayout.DragEdge.Left && viewHolder.discountText != null) {
**viewHolder.discountText.setTimeByTag().play();**
LogUtils.LogE("Left Open...");
}
}
#Override
public void onOpen(SwipeLayout layout, SwipeLayout.DragEdge edge) {
super.onOpen(layout, edge);
if (edge == SwipeLayout.DragEdge.Left && viewHolder.discountText != null) {
viewHolder.discountText.setTimeByTag().play();
LogUtils.LogE("Left Open...");
}
}
#Override
public void onClose(SwipeLayout layout, SwipeLayout.DragEdge edge) {
if (edge == SwipeLayout.DragEdge.Left && viewHolder.discountText != null) {
viewHolder.discountText.stop();
LogUtils.LogE("Left Close!");
}
}
};
public void openLeft() {
LogUtils.LogE("onClick openLeft-");
if (getSwipeLayout() == null){
LogUtils.LogE("onClick -null-");
return;
}
if (!getSwipeLayout().isOpen()) {
getSwipeLayout().open(true, SwipeLayout.DragEdge.Left);
LogUtils.LogE("onClick --");
}
}
all the codes working in other my fragments.I need some idea what's the reason that it not give true action that swipe to left.
EDIT:
Here is the Logs:
In this picture I have 2 items there which it's in my favorite page.The last one item has end date that will be visible the icon(ImageView).When pressing the icon,it should swipe to left side but it's not working and give the result like this picture which I'm shared.
EDIT
There is something more.I had looked the codes in debug mode and give here an message:
but put define swipeLayout into my code:
sl.setShowMode(SwipeLayout.ShowMode.LayDown);
sl.setDragEdges(SwipeLayout.DragEdge.Left, SwipeLayout.DragEdge.Right);
sl.setBottomViewIds(R.id.productBottomLeft, R.id.productBottomRight, SwipeLayout.EMPTY_LAYOUT, SwipeLayout.EMPTY_LAYOUT);
TextView button = SwipeLayout.findViewById(R.id.yourButtonId) //the bottom view;
button.setOnClickListener(v -> yourMethod());
My button use code that shows and hides the views:
public void onClick (View v){
if (What code you need to enter here to determine hidden views or shown)
{
testActivity.setVisibility(View.VISIBLE);
}
else
{
testActivity.setVisibility(View.GONE);
}
}
What code I need to add in the "if()", so that clicking on my button was checked condition. If the activity is hidden, it should be shown, and Vice versa. If the views is shown, hide it.
I'm guessing since you are using setVisibility, that you want to check the visibility of a View , not an Activity.
In that case you just use getVisibility()
(I used != cause the visibility could be IINVISIBLE as well, change per your needs) :
public void onClick (View v){
if (testActivity.getVisibility() != View.VISIBLE)
{
testActivity.setVisibility(View.VISIBLE);
}
else
{
testActivity.setVisibility(View.GONE);
}
} });
Don't understand why, but only that removed the answer of a man who has solved my problem. Here is his response, and this code works:
public void onClick (View v){
if ((testActivity.getVisibility() == View.VISIBLE))
{
testActivity.setVisibility(View.GONE);
}
else
{
testActivity.setVisibility(View.VISIBLE);
}
I have implemented a ListView that has the functionality that you see in many apps, where user scrolls to bottom and it loads more, that OnScrollListener is this:
public class OnScrolledToEndListener implements AbsListView.OnScrollListener
{
private int prevLast;
#Override
public void onScrollStateChanged(AbsListView absListView, int i)
{
}
#Override
public void onScroll(AbsListView absListView, int first, int visible, int total)
{
int last = first + visible;
if (last == total)
{
if (prevLast != last)
{
prevLast = last;
onScrolledToEnd();
}
}
}
public void onScrolledToEnd()
{
}
}
Now the problem is that when a user has scrolled to the bottom of a list, and hits the refresh button in my app, I want it to start over at the top of the list, because if it stays at the bottom of the list, then the scroll listener will immediately trigger. The best way I've found to solve this is by doing the following before executing the refresh:
mListView.setSelection(0);
mListView.post(
new Runnable()
{
#Override
public void run()
{
mListView.setVisibility(View.GONE);
mLoadingLayout.setVisibility(View.VISIBLE); //this is basically a progressbar
// do the refresh
}
}
);
But there is a slight flicker when the list scrolls to the top. Any ideas on how to make it look better?
I figured out the solution. Apparently setting the ListView to View.GONE makes it not update its layout, so I set it to View.INVISIBLE instead and it worked. I didn't even have to use a Runnable.
mListView.setSelection(0);
mListView.setVisibility(View.INVISIBLE);
mLoadingLayout.setVisibility(View.VISIBLE);