Search Unity

How to find out which part of the element is visible?

Discussion in 'UIElements' started by Devi-User, Dec 28, 2018.

  1. Devi-User

    Devi-User

    Joined:
    Apr 30, 2016
    Posts:
    61
    I come across this case not for the first time, so I think it's worth describing it here.
    I have problems from the fact that I can not reliably find out what part of the element is now visible on the screen. Part of the element can be hidden outside the scope of the parent element. So for example if we have a graph or scroll. I would like to be able to recognize such things in order to more correctly shape the behavior of objects.
    I see that this can be solved head-on by manually searching for parentes and trying to calculate it based on the existing properties. However, I think there should be a simpler solution. In the end, 'overflow' somehow works.
    I think this can come in handy quite often, for example, without this, it is difficult to create something like virtualization like in WPF, which is needed when it comes to really huge data displayed in the interface.
    If there is a way to know the visible area, could you tell us about it?
    If not, is it possible to add a way to do this built into unity?
     
  2. Devi-User

    Devi-User

    Joined:
    Apr 30, 2016
    Posts:
    61
    This works, but there is no certainty that it takes rotation into account in the desired way.
    Code (CSharp):
    1.         public static bool TryGetLocalVisibleArea(this VisualElement element, out Rect rect)
    2.         {
    3.             if (element == null)
    4.             {
    5.                 rect = new Rect();
    6.                 return false;
    7.             }
    8.            
    9.             if (TryGetWorldVisibleArea_int(element, out rect))
    10.             {
    11.                 rect =  element.WorldToLocal(rect);
    12.                 return true;
    13.             }
    14.             return false;
    15.         }
    16.  
    17.        
    18.         public static bool TryGetWorldVisibleArea(this VisualElement element, out Rect rect)
    19.         {
    20.             if (element == null)
    21.             {
    22.                 rect = new Rect();
    23.                 return false;
    24.             }
    25.            
    26.             return TryGetWorldVisibleArea_int(element, out rect);
    27.         }
    28.         private static bool TryGetWorldVisibleArea_int(this VisualElement element, out Rect rect)
    29.         {
    30.             var currentElement = element;
    31.             var currentBound = currentElement.worldBound;
    32.             while (currentElement.parent != null)
    33.             {
    34.                 if (!TryOverlap(currentBound, currentElement.parent.worldBound, out currentBound))
    35.                 {
    36.                     rect = currentBound;
    37.                     return false;
    38.                 }
    39.                 currentElement = currentElement.parent;
    40.             }
    41.             rect = currentBound;
    42.             return element.parent != null;
    43.         }
    44.  
    45.         private static bool TryOverlap(Rect a, Rect b, out Rect c)
    46.         {
    47.             var x0 = Mathf.Max(a.xMin, b.xMin);
    48.             var y0 = Mathf.Max(a.yMin, b.yMin);
    49.             var x1 = Mathf.Min(a.xMax, b.xMax);
    50.             var y1 = Mathf.Min(a.yMax, b.yMax);
    51.             c = new Rect(x0, y0, x1 - x0, y1 - y0);
    52.             if (x0 >= x1 || y0 >= y1)
    53.                 return false;
    54.             return true;
    55.         }
     
  3. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    295
    We already have a few virtualized elements: ListView, GraphView, and TreeView (still internal for now). We implemented all of these by using a VisualElement representing the "viewport" and a (potentially bigger) child element representing the "container".

    The viewport element will be the size of the visible area you are referring to and this makes it trivial to determine it's size and shape.

    The key is to make the inner container element positioned absolutely so it does not alter the viewport parent element and can be sized independently.