Каков наилучший способ проверить, видно ли в окне вид?

Каков наилучший способ проверить, видно ли в окне вид?

У меня есть CustomView, который является частью моего SDK, и любой может добавить CustomView в свои макеты. Мой CustomView предпринимает некоторые действия, когда он отображается пользователю периодически. Поэтому, если просмотр становится невидимым для пользователя, тогда ему необходимо остановить таймер, и когда он снова станет видимым, он должен перезапустить свой курс.

Но, к сожалению, нет определенного способа проверить, станет ли мой пользовательский интерфейс видимым или невидимым для пользователя. Есть несколько вещей, которые я могу проверить и послушать:

onVisibilityChange //it is for view's visibility change, and is introduced in new API 8 version so has backward compatibility issue onWindowVisibilityChange //but my CustomView can be part of a ViewFlipper's Views so it can pose issues onDetachedFromWindows //this not as useful onWindowFocusChanged //Again my CustomView can be part of ViewFlipper's views. 

Поэтому, если кто-либо сталкивался с такими проблемами, пожалуйста, бросьте какой-то свет.

    onDraw() вызывается каждый раз, когда нужно onDraw() представление. Когда представление выключено, то onDraw () никогда не вызывается. Когда крошечный бит представления становится видимым для пользователя, вызывается onDraw (). Это не идеально, но я не вижу другого вызова для использования, поскольку я хочу сделать то же самое. Не забудьте вызвать super.onDraw или представление не будет нарисовано. Будьте осторожны, чтобы изменить что-либо в onDraw, что заставляет представление быть недействительным, поскольку это вызовет другой вызов onDraw.

    Если вы используете listview, getView может использоваться всякий раз, когда ваш список будет показан пользователю.

    Очевидно, что действие onPause() называется всеми вашими представлениями, все закрыты и не видны пользователю. Возможно, вызывая invalidate () для родителя, и если ondraw () не вызывается, то он не отображается.

    В моем случае следующий код работает лучше всего для прослушивания, если вид виден или нет:

     @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); Log.e(TAG, "is view visible?: " + (visibility == View.VISIBLE)); } 

    В дополнение к view.getVisibility () есть view.isShown ().
    IsShown проверяет дерево просмотров, чтобы определить, видны ли все предки.

    Хотя, это не обрабатывает препятствия, только взгляды, которые скрыты или ушли либо сами, либо один из его родителей.

    Это метод, который я использовал довольно много в своих приложениях, и у меня получилось неплохо для меня:

     static private int screenW = 0, screenH = 0; @SuppressWarnings("deprecation") static public boolean onScreen(View view) { int coordinates[] = { -1, -1 }; view.getLocationOnScreen(coordinates); // Check if view is outside left or top if (coordinates[0] + view.getWidth() < 0) return false; if (coordinates[1] + view.getHeight() < 0) return false; // Lazy get screen size. Only the first time. if (screenW == 0 || screenH == 0) { if (MyApplication.getSharedContext() == null) return false; Display display = ((WindowManager)MyApplication.getSharedContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); try { Point screenSize = new Point(); display.getSize(screenSize); // Only available on API 13+ screenW = screenSize.x; screenH = screenSize.y; } catch (NoSuchMethodError e) { // The backup methods will only be used if the device is running pre-13, so it's fine that they were deprecated in API 13, thus the suppress warnings annotation at the start of the method. screenW = display.getWidth(); screenH = display.getHeight(); } } // Check if view is outside right and bottom if (coordinates[0] > screenW) return false; if (coordinates[1] > screenH) return false; // Else, view is (at least partially) in the screen bounds return true; } Размер static private int screenW = 0, screenH = 0; @SuppressWarnings("deprecation") static public boolean onScreen(View view) { int coordinates[] = { -1, -1 }; view.getLocationOnScreen(coordinates); // Check if view is outside left or top if (coordinates[0] + view.getWidth() < 0) return false; if (coordinates[1] + view.getHeight() < 0) return false; // Lazy get screen size. Only the first time. if (screenW == 0 || screenH == 0) { if (MyApplication.getSharedContext() == null) return false; Display display = ((WindowManager)MyApplication.getSharedContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); try { Point screenSize = new Point(); display.getSize(screenSize); // Only available on API 13+ screenW = screenSize.x; screenH = screenSize.y; } catch (NoSuchMethodError e) { // The backup methods will only be used if the device is running pre-13, so it's fine that they were deprecated in API 13, thus the suppress warnings annotation at the start of the method. screenW = display.getWidth(); screenH = display.getHeight(); } } // Check if view is outside right and bottom if (coordinates[0] > screenW) return false; if (coordinates[1] > screenH) return false; // Else, view is (at least partially) in the screen bounds return true; } 

    Чтобы использовать его, просто перейдите в любой вид или подкласс представления (IE, почти все, что рисуется на экране в Android.) Это вернет true если оно на экране или false если это не … довольно интуитивно, я думаю.

    Если вы не используете вышеуказанный метод как статический, то вы, вероятно, можете получить контекст каким-либо другим способом, но для того, чтобы получить контекст приложения из статического метода, вам нужно сделать следующие две вещи:

    1 – Добавьте в свой тег application следующий атрибут:

     android:name="com.package.MyApplication" 

    2 – добавьте в класс, который расширяет приложение, например:

     public class MyApplication extends Application { // MyApplication exists solely to provide a context accessible from static methods. private static Context context; @Override public void onCreate() { super.onCreate(); MyApplication.context = getApplicationContext(); } public static Context getSharedContext() { return MyApplication.context; } } 

    Это можно проверить с getGlobalVisibleRect метода getGlobalVisibleRect . Если прямоугольник, возвращаемый этим методом, имеет тот же размер, что и View , то текущий View полностью отображается на экране.

     /** * Returns whether this View is completely visible on the screen * * @param view view to check * @return True if this view is completely visible on the screen, or false otherwise. */ public static boolean onScreen(@NonNull View view) { Rect visibleRect = new Rect(); view.getGlobalVisibleRect(visibleRect); return visibleRect.height() == view.getHeight() && visibleRect.width() == view.getWidth(); } 

    Если вам нужно рассчитать процент видимости, вы можете сделать это, используя квадратный расчет:

     float visiblePercentage = (visibleRect.height() * visibleRect.width()) / (float)(view.getHeight() * view.getWidth()) 

    При рассмотрении подобной проблемы, когда мне нужно было знать, есть ли у этого вида какое-то другое окно поверх этого, я использовал это в своем обычном представлении:

     @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); if (!hasWindowFocus) { } else { } } 

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

      getViewTreeObserver().addOnScrollChangedListener(this); getViewTreeObserver().addOnGlobalLayoutListener(this); 

    Я использую этот код для анимации вида один раз, когда он видим пользователю.

    Следует рассмотреть 2 случая.

    1. Ваше мнение не отображается на экране. Но это будет видно, если пользователь прокрутил его

       public void onScrollChanged() { final int i[] = new int[2]; this.getLocationOnScreen(i); if (i[1] <= mScreenHeight - 50) { this.post(new Runnable() { @Override public void run() { Log.d("ITEM", "animate"); //animate once showValues(); } }); getViewTreeObserver().removeOnScrollChangedListener(this); getViewTreeObserver().removeOnGlobalLayoutListener(this); } } 
    2. Ваше представление изначально находится на экране. (Не в другом месте, невидимом для пользователя в scrollview, он находится вначале на экране и видим для пользователя)

       public void onGlobalLayout() { final int i[] = new int[2]; this.getLocationOnScreen(i); if (i[1] <= mScreenHeight) { this.post(new Runnable() { @Override public void run() { Log.d("ITEM", "animate"); //animate once showValues(); } }); getViewTreeObserver().removeOnGlobalLayoutListener(this); getViewTreeObserver().removeOnScrollChangedListener(this); } } 

    Вы можете добавить в свой конструктор CustomView объект onScrollChangedListener из ViewTreeObserver

    Поэтому, если в вашем представлении прокручивается экран, вы можете вызвать view.getLocalVisibleRect () и определить, является ли ваш взгляд частично вне экрана …

    Вы можете взглянуть на код моей библиотеки: PercentVisibleLayout

    Надеюсь, поможет!