Author Topic: Dragging panel contents one at a time (regardless of drag distance)  (Read 4036 times)

pek

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 13
    • View Profile
Hi there,

I have a scene which contains a list of tutorial pages that the user can drag them. This is the scene's setup:

- Root [UICamera]
- - Tutorial
- - - Pagination [UITable]
- - - - Previous Page
- - - - Page1 dot
- - - - Page2 dot
- - - - Page3 dot
- - - - Next Page
- - - Pages [UIPanel, UIDraggablePanel]
- - - - PageContainer [UIGrid, UICenterOnChild]
- - - - - Page1 [UIDragPanelContents]
- - - - - Page2 [UIDragPanelContents]
- - - - - Page3 [UIDragPanelContents]

So far everything is working as excepted. However, I'd like to make the two following changes:

1. No matter how fast or how far the user drags, he can only move to the next page (he cannot overshoot and go from Page 1 to Page 3)
2. No matter how fast or how far the user drags, the pages move at a specific speed

In other words, I'm trying to emulate how the iOS home screen icon pages behave. I can drag 2 pixels or 2000 pixels, I will always move to the next page. Also, I can swipe slowly and drag only 2 pixels or I can swipe from one end of the screen to the other in 0.2 seconds and I still will move only one screen.

Can you give me some guidance? Thank you.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Dragging panel contents one at a time (regardless of drag distance)
« Reply #1 on: August 23, 2013, 03:10:32 PM »
Don't use the draggable panel. Create your own class. You need custom behaviour, so you need a custom script.

pek

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 13
    • View Profile
Re: Dragging panel contents one at a time (regardless of drag distance)
« Reply #2 on: August 23, 2013, 03:48:57 PM »
I see. I'm fine with that.

Do you have any recommendations for how to do this? What should I look for? I think I'll need to subclass UIDraggablePanel and override some things, but not sure where to start.

I'll start poking around.

Thanks.

Spek

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 2
    • View Profile
Re: Dragging panel contents one at a time (regardless of drag distance)
« Reply #3 on: September 02, 2013, 06:38:53 AM »
join a question

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Dragging panel contents one at a time (regardless of drag distance)
« Reply #4 on: September 02, 2013, 05:55:19 PM »
I can't recommend anything specific. Two ways to approach it, and if it was me, I'd create a custom script from scratch. Draggable panel is a pretty complex script that even I decided to rewrite for the upcoming GUI.

pek

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 13
    • View Profile
Re: Dragging panel contents one at a time (regardless of drag distance)
« Reply #5 on: September 03, 2013, 04:20:09 PM »
So I solved this by creating a copy of UICenterOnChild component, and changing the way it sets what child to center on. Luckily, I didn't have to touch UIDraggablePanel at all ;)

Here are the short list of changes:

When the component initializes, I keep a reference of the child that is currently centered to.

Line 64 changes from:
  1. if (mDrag.panel == null) return;
to:
  1. if (mDrag.panel == null)
  2. {
  3.   List<Transform> closestList = GameObjectUtils.GetChildrenSortedByDistance(this.transform, this.transform.position);
  4.   mCenteredObject = closestList[0].gameObject;
  5.   return;
  6. }

Now, I can make sure that I will never overshoot by checking the new child's index and the last child's index in the sorted by distance list. If it's greater than 1, I will clamp it, so it will always choose 1 towards the moment and not further. Of course, this assumes that the child game objects are named in a way so that they are sorted by name (i.e. Page1, Page2, Page3, etc).

Line ~104 changes from:
  1. if (closest != null)
  2. {
  3.   mCenteredObject = closest.gameObject;
to:
  1. if (closest != null)
  2. {
  3.   if (mCenteredObject != null)
  4.   {
  5.     // Overshoot protection
  6.     int startingIndex = GameObjectUtils.GetChildIndex(trans, mCenteredObject.transform);
  7.     if (Mathf.Abs(closestIndex - startingIndex) > 1)
  8.     {
  9.       int clampedIndex = Mathf.Clamp(closestIndex - startingIndex, -1, 1);
  10.       int validIndex = Mathf.Clamp(startingIndex + clampedIndex, 0, trans.childCount - 1);
  11.       closest = trans.GetChild(validIndex);
  12.     }
  13.   }
  14.   mCenteredObject = closest.gameObject;

Finally, to make it super sensitive, I multiply the momentum with 10,000 so that the littlest move will force it to move to the next child, but due to the overshoot protection, it will never go farther than just the next.

Line ~81 changes from:
  1. Vector3 offsetCenter = center - mDrag.currentMomentum * (mDrag.momentumAmount * 0.1f);
to:
  1. Vector3 offsetCenter = center - (mDrag.currentMomentum * 10000) * (mDrag.momentumAmount * 0.1f);

Finally, on the UIDraggablePanel, I set the scale.x to 0.6 (this is a case-by-case thing though), so that, no matter how fast the user tries to swipe the page, the speed won't allow it to go past one page.