2010-09-04 151 views
19

检查视窗是否可见的最佳方法是什么?检查视窗是否可见的最佳方法是什么?

我有一个CustomView,它是我的SDK的一部分,任何人都可以将CustomView添加到他们的布局。当我的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.
因此,如果任何人遇到过这种问题,请投入一些光。每次需要绘制视图时调用

回答

7

onDraw()。当视图不在屏幕上时,onDraw()永远不会被调用。当视图的一小部分变得对用户可见时,则调用onDraw()。这不是理想的,但我不能看到另一个电话使用,因为我想做同样的事情。请记住调用super.onDraw,否则视图将不会绘制。小心改变onDraw中导致视图无效的任何内容,因为这会导致对onDraw的另一次调用。

如果您使用的是一个列表视图,那么只要您的列表视图显示给用户,就可以使用getView。

很明显,活动onPause()被称为所有您的意见全部被掩盖,并且不可见的用户。也许在父级调用invalidate(),如果ondraw()没有被调用,那么它是不可见的。

+2

我也不得不这样做[这](http://stackoverflow.com/questions/7781892/own -defined-layout-ondraw-method-not-getting-called/7784369#7784369)为了这个工作 – 2014-08-20 23:21:34

4

这是一个方法,我已经使用了不少我的应用程序,并不得不为我工作得非常好:

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

一个视图应该有一个关联的上下文(通过getContext()),所以你不能使用它而不是应用/共享上下文?这样做会节省很多代码。 – greg7gkb 2013-07-25 21:51:05

+0

自2012年以来,我还没有碰过Android,但是我记得我需要这个代码在启动过程中很早就能够运行,在上下文全部被分配之前。我想不起为什么我需要这个。 – ArtOfWarfare 2013-07-26 03:01:08

+0

我觉得这个方法只会检查视图是否在屏幕范围内。要检测视图是否实际显示,您需要将其与isShown()结合使用。 – 2016-09-23 12:48:24

3

除了view.getVisibility()之外,还有view.isShown()。
isShown检查视图树以确定是否所有的祖先都可见。

虽然这并不处理被阻挡的视图,但只有隐藏或在其自己或其父母之一中丢失的视图。

+0

这真的帮了我(view.isShown())。感谢+1。 – 2015-06-22 16:12:56

6

在我的情况下,下面的代码工作最好听,如果视图是可见或不可见:

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

在处理类似的问题,在这里我需要知道,如果视图具有在它上面的一些其他窗口,我在我的自定义视图中使用这样的:

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

    } else { 

    } 
} 
0
把定制的视图

,设置听众:

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. 你的观点最初是在屏幕上。(而不是在别的地方看不到用户在滚动视图,它是最初在屏幕上可见的用户)

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

这可以使用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()) 
相关问题