Обработка изменения видимости без переопределения

Есть ли способ справиться с изменением видимости вида (скажем, из GONE в VISIBLE) без переопределения вида?

Что-то вроде View.setOnVisibilityChangeListener();?

6 ответов

Решение

Вы можете использовать GlobalLayoutListener определить, есть ли какие-либо изменения в видимости представлений.

myView.setTag(myView.getVisibility());
myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int newVis = myView.getVisibility();
        if((int)myView.getTag() != newVis)
        {
            myView.setTag(myView.getVisibility());
            //visibility has changed
        }
    }
});

Kotlin кажется намного проще, если кому-то это нужно. Использование аналогичного подхода в качестве принятого ответа также будет работать (установка тега), если вам нужно отслеживать исходящие из невидимого, но я использовал это для GONE -> VISIBLE -> GONE

      binding.myView.viewTreeObserver.addOnGlobalLayoutListener {
    when (binding.myView.visibility) {
        View.VISIBLE -> {
            
        }
        View.GONE -> {
            
        }
    }
}

Вместо подклассов вы можете использовать украшение:

class WatchedView {

    static class Listener {
        void onVisibilityChanged(int visibility);
    }

    private View v;
    private Listener listener;

    WatchedView(View v) {
        this.v = v;
    }

    void setListener(Listener l) {
        this.listener = l;
    }

    public setVisibility(int visibility) {
        v.setVisibility(visibility);
        if(listener != null) {
            listener.onVisibilityChanged(visibility);
        }
    }

}

затем

 WatchedView v = new WatchedView(findViewById(R.id.myview));
 v.setListener(this);

Взгляни на ViewTreeObserver.OnGlobalLayoutListener, Как написано в документации, его метод обратного вызова onGlobalLayout() вызывается при изменении состояния глобального макета или видимости представлений в дереве представлений. Таким образом, вы можете попытаться использовать его для обнаружения изменений видимости.

Мы можем соответствовать видимостиTextViewпо потоку/живым данным. Затем прослушайте просмотр видимости через Flow/LiveData.

      class ViewModel : ViewModel() {

    private val _textNameVisibility = MutableStateFlow(View.VISIBLE)
    val textNameVisibility: LiveData<Int> = _textNameVisibility.asLiveData()


    fun setTextNameVisibility(visibility: Int) {
        _textNameVisibility.value = visibility
    }
}

Об действии/фрагменте

      viewModel.textNameVisibility.observe(this) {
    tvName.visibility = it
    Log.i("TAG", "View visibility change" + it)
}

Обратите внимание, что нам нужно использоватьsetTextNameVisibilityизменить видимость представления.
ИStateFlowне будет выдавать одно и то же значение (аналогичноdistinctUntilChanged), так что не нужно заботиться о предыдущей видимости

      import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import android.widget.Toast
import java.lang.ref.WeakReference


class MyImageView : ImageView {
    var mListener: WeakReference<VisibilityChangeListener>? = null

    interface VisibilityChangeListener {
        fun onVisibilityChanged(visibility: Int)
    }

    constructor(context: Context?) : super(context) {}
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
    constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
        context,
        attrs,
        defStyle
    ) {
    }

    fun setVisibilityChangeListener(listener: VisibilityChangeListener) {
        mListener = WeakReference(listener)
    }

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        super.onVisibilityChanged(changedView, visibility)
        Toast.makeText(context,visibility.toString(), Toast.LENGTH_SHORT).show()

        if (mListener != null && changedView === this) {
            val listener = mListener!!.get()
            listener?.onVisibilityChanged(visibility)
        }
    }
}
Другие вопросы по тегам