Monday, October 1, 2018

When does setVisibility() not fire onVisibilityChanged() in a view?

Leave a Comment

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.

3 Answers

Answers 1

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.

Answers 2

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     } }  

Answers 3

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.

  1. When visibility is VISIBLE.
  2. 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);     } } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment