Hey everyone,
I've seen a few threads in the past mentioning this issue, and having struggled with it myself, I decided to post a guide on the solution that I've come up with. I quickly want to point out that I have not yet battle tested this code or profiled it, or spent extra time optimizing, and I in no way guarantee its fitness or reliability. So use at your own risk! That said, it seems to be performing admirably in my game so far. Carrying on...
The problemItems outside of the clip area on a UIDraggablePanel are still active. I think most people probably don't want their buttons clickable when they aren't visible. The typical NGUI solution is to put blocking colliders around your clipping area, above (in the z dimension) your clipped content. This works just fine but requires some extra labor and for some is annoying to deal with, especially in instances (like in my own game) where multiple UIDraggablePanels are adjacent to one another.
The code based solutionI've written a component that monitors whether or not it is within the clipping rect of a UIDraggablePanel. When its state (in-bounds, or out-of-bounds) changes, it fires a delegate. You also get to define the rectangle you want to use for determining whether or not your component is considered in bounds.
Here's an illustration showing how it works:

If you don't want to use delegates, you can also add in your own code here. Either way, you can write your own code that handles what to do in this situation. I've included some examples via in line comments. I'm currently using it to automatically disable / enable the collider of the GameObject the component is attached to.
How to useYou'll need to modify two NGUI files in order to get the component to compile:
- Add the following function to the UIPanel class in UIPanel.cs:
/// <summary>
/// Returns a Rect which describes the clipping area of this panel in Screen (pixel) coordinates.
/// This is the same area that is drawn with a magenta outline in the Scene gizmos.
/// </summary>
public Rect ClippingRectScreen
{
get
{
Vector2 size
= new Vector2
(mClipRange
.z, mClipRange
.w);
if (size.x == 0f) size.x = mScreenSize.x;
if (size.y == 0f) size.y = mScreenSize.y;
Vector3 screenPos = UICamera.currentCamera.WorldToScreenPoint(transform.position);
r.width = size.x;
r.height = size.y;
r
.center = new Vector2
(mClipRange
.x + screenPos
.x, mClipRange
.y + screenPos
.y);
return r;
}
}
- Add the following function to the UIDraggablePanel class in UIDraggablePanel.cs:
/// <summary>
/// Returns a Rect which describes the clipping area of this panel in Screen (pixel) coordinates.
/// This is the same area that is drawn with a magenta outline in the Scene gizmos.
/// </summary>
public Rect ClippingRectScreen
{
get
{
return mPanel.ClippingRectScreen;
}
}
Now you're ready to use the component, which is attached. It uses a simple Axis Aligned Bounding Box hit test (
not a Raycast) to determine whether or not the component is within the clip rect of the panel. The component's "hit rectangle" (named boundsRect) is defined explicitly on the component, though you can have the component simply match the dimensions of the collider on the same GameObject if you choose. The rect is shown via a Gizmo -- a pink box in the scene view. I've found that having the rect around 50-60% of the size of the collider results in the behavior I'm looking for.
It's relatively short and fairly heavily documented in-line, so read in there if you'd like to know more about it, or modify it. If you want to use a different type of collision test, for example, you can use my code as a starting point for how to get the 2 rectangles in question.
I hope this helps some people! Also feel free to check out my company's site or my twitter if you're interested, where I periodically post about Unity gamedev topics.