Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine if a view is on screen - Android

Tags:

I'm a little bit stuck with this one - first and foremost, the following link has been useful however I've come up with a bit of an issue with visibility:

The link: Check view visibility

I have a scroll view (parent) and a number of sub-views (LinearLayout -> TableLayout) etc. There are a number of items I set to View.GONE within the XML (android:visibility="gone").

I have some simple code to determine whether it is visible or not using getVisibility() however when I set the item to View.VISIBLE and try to immediately getDrawingRect() I get a Rect with zeros across the board. Any further click gets the correct coordinates.

Now this could be because the view has never been drawn (as defined in the XML) causing it to return no coordinates however I do set View.VISIBLE before trying to determine screen visibility. Could it be that I need to get some kind of callback from say the onDraw()? or perhaps set the view visibility of hidden items within code. A bit annoying ;(

Some code:

Rect scrollBounds = new Rect(); scroll.getHitRect(scrollBounds);  Rect viewBounds = new Rect();  if (view.getVisibility() == View.GONE) {     view.setVisibility(View.VISBLE)       viewBounds.getDrawingRect(viewBounds);     if (!Rect.intersects(scrollBounds, viewBounds) {         // do somthing     }  } 

Layouts area as follows:

  • ScrollView
    • LinearLayout
      • TableLayout
        • Button
        • HiddenView

Of course, it's highly likely I'm going about this the wrong way altogether - basically I just want to make sure that the scrollview positions itself so the view that has become visible can be seen in it's entirety.

If any other information is required, let me know!

like image 988
Hamz4h_ Avatar asked Apr 08 '13 08:04

Hamz4h_


People also ask

What is Android visibility?

A View's visibility status is of Integer type and can have one of three options: VISIBLE (0) - The View is visible to the user. INVISIBLE (4) - The View is invisible to the user, but still takes up space in the layout. GONE (8) - The View is invisible, and it does not take up space in the layout.


2 Answers

Ok so thanks to OceanLife for pointing me in the right direction! There was indeed a callback required and ViewTreeObserver.OnGlobalLayoutListener() did the trick. I ended up implementing the listener against my fragment class and picked it up where I needed it. Thanks for the warning too regarding the multiple calls, I resolved this using the removeOnGlobalLayoutListener() method - works a charm.

Code:

...  // vto initialised in my onCreateView() method  vto = getView().getViewTreeObserver(); vto.addOnGlobalLayoutListener(this);  ...  @Override     public void onGlobalLayout() {          final int i[] = new int[2];         final Rect scrollBounds = new Rect();          sView.getHitRect(scrollBounds);         tempView.getLocationOnScreen(i);          if (i[1] >= scrollBounds.bottom) {             sView.post(new Runnable() {                 @Override                 public void run() {                     sView.smoothScrollTo(0, sView.getScrollY() + (i[1] - scrollBounds.bottom));                 }             });         }          vto.removeOnGlobalLayoutListener(this);     } 

Just got to do some cleaning up now ...

like image 154
Hamz4h_ Avatar answered Sep 20 '22 09:09

Hamz4h_


So, if I am reading this right the issue you are having is that you want to find out the dimensions of some view in your layout to find out whether you have an intersection with the parent ScrollView.

What I think you are seeing (as you alluded to) is the instruction to draw the view being dispatched, and then in some sort of race-condition, the renderer resolving the measurements for the layout and the actual render where view objects get real sizes. One way to find out what sort of dimensions a view has on screen is to use the layout tree-listener. We use this observer to resolve a screen's dimensions when leveraging the Google Charts API, which requires a pixel width and height to be defined... which of course on Android is probably the biggest problem facing developers. So observe (pun intended);

final ViewTreeObserver vto = chart.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {    /**    * @see android.view.ViewTreeObserver.OnGlobalLayoutListener#onGlobalLayout()    */   @SuppressWarnings("deprecation")   @Override   public void onGlobalLayout() {     if (view.getVisibility() == View.GONE) {       view.setVisibility(View.VISBLE)       viewBounds.getDrawingRect(viewBounds);       if (!Rect.intersects(scrollBounds, viewBounds) {         // do something       }      }   } }); 

Word of warning the onGlobalLayout will get called multiple times as the renderer closes in on the final solution. The last call is the one we take.

This will provide you with a mechanism for performing actions on a drawn view like getting a view component's width and height. Hope that helps you out.

Aside: The clever chaps over at Square have designed a FEST hamcrest library that will allow you to write a test for this alongside Robotium. Check it out.

like image 33
BrantApps Avatar answered Sep 19 '22 09:09

BrantApps