Recreating iPhone Home Screen in Unity

I am trying to recreate a UI menu that has functionality similar to the iPhone’s home screen:

  • If a user drags anywhere on the menu (including on a button), it should drag the whole page left/right depending on the user’s drag.
  • If a user clicks and holds motionlessly on a single button, it “dislodges” the button so that it can be dragged around.

43704-ios-home-screen-resized.jpg

I have all of my functionality working, including the dislodge. The one exception being that I’m running into a situation where I’m not sure how to transfer the drag message consumed by a button onto the backing scroll container if the user has not clicked long enough on a single button to “dislodge” it.

That is, I place my finger onto a button and drag (with the intention of dragging the entire page) but I’m not sure how to redirect the same drag message onto the ScrollRect of my backing container. Instead, my button consumes the OnDrag message and the page is not scrolled. The only method of scrolling the page is simply dragging on an empty part of the container where there is no button.

alt text

I’m using UI elements from Unity’s 4.6 UI:

  • I am using a ScrollRect to represent the backing container with all of my buttons

  • I’m using a GridLayout to resize and pad my buttons

  • I’m using a regular UI.Button class on each of my buttons

  • I’m using the following EventSystem interfaces to catch and handle input for my buttons:
    IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler

Is there something already built into Unity that can allow me to transfer/redirect the drag message from one GameObject to another while the drag is still in process? Or do I need to rebuild parts of the UI from scratch to support this?

One way that works is to store the PointerEventData and use ExecuteEvents to end the drag on the current object and start the drag on the new target object.

public GameObject other;
float time = 0;

PointerEventData data;

void Update() {
	if(time > 0) {
		time = Mathf.Max(time - Time.deltaTime, 0);

		if(time == 0) {
			ExecuteEvents.Execute<IEndDragHandler>(gameObject, data, ExecuteEvents.endDragHandler);
			data.pointerDrag = other;
			ExecuteEvents.Execute<IBeginDragHandler>(other, data, ExecuteEvents.beginDragHandler);
		}
	}
}