Подтвердить что ты не робот

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

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

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

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

onVisibilityChange //it is for view 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 Views so it can pose issues
onDetachedFromWindows //this not as useful
onWindowFocusChanged //Again my CustomView can be part of ViewFlipper views.
Так что, если кто-то сталкивался с такими проблемами, пожалуйста, бросьте какой-то свет.
4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

Это можно проверить с помощью метода 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()) 

Ответ 6

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

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

   } else {

   }
}

Ответ 7

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

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

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

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

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

    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);
        }
    }
    
  • Ваше представление изначально отображается на экране. (Не в другом месте, невидимом для пользователя в 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);
     }
    }
    

Ответ 8

вы можете добавить в свой CustomView constractor a onScrollChangedListener из ViewTreeObserver

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

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

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