简体   繁体   English

什么时候setVisibility()不会触发视图中的onVisibilityChanged()?

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

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. 我有一个问题,在我在自定义视图中调用setVisibility(GONE)的特定情况下,它的onVisibilityChanged方法没有被调用,它实际上不会隐藏视图,尽管getVisibility()返回8 (或GONE )。

Here is how I know the visibility changes but onVisibilityChanged is not called. 以下是我知道可见性更改的方法,但未调用onVisibilityChanged。

@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: 通常当我调用hide()我会在日志中看到这些行:

before hide visibility: 0 在隐藏可见性之前:0

onVisibilityChanged: 8 onVisibilityChanged:8

setVisibility: 8 setVisibility:8

after hide visibility: 8 隐藏能见度后: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 : 但是在一个特殊的情况下,当我调用hide()我在日志中得到这些行,之后视图不会被隐藏,尽管getVisibility()返回8

before hide visibility: 0 在隐藏可见性之前:0

setVisibility: 8 setVisibility:8

after hide visibility: 8 隐藏能见度后:8

So when in general does this happen? 那么一般情况下会发生这种情况吗? When does setVisibility not call onVisibilityChanged ? 什么时候setVisibility不调用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: 对setVisibility的调用如下所示:

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: setFlags方法是一个很长的方法,其中一组不同的视图属性被更改和处理,但值得注意的部分是:

 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 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. 如上所述,只有在可见性发生变化时才会调用onVisibilityChanged

public void hide(){
    setVisibility(GONE);
}

This will be called in two cases. 这将在两种情况下被调用。

  1. When visibility is VISIBLE . 当能见度VISIBLE
  2. When visibility is INVISIBLE . 当能见度INVISIBLE

This will not be called if View visibility is already set to GONE. 如果视图可见性已设置为GONE,则不会调用此方法。

Solution

So how can you capture all the events of visibility? 那么如何捕获所有可见性事件?

Override setVisibility method in your custom view class. 覆盖自定义视图类中的setVisibility方法。 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. 如果您确定,在可见性更改时,您的代码会调用onVisibilityChangedsetVisibility 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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM