Author Topic: Scrollable (Draggable) Dynamic UILabel  (Read 16144 times)

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Scrollable (Draggable) Dynamic UILabel
« on: March 20, 2013, 08:24:55 AM »
Hi!

I develop "News Panel" with NGUI (see attach).
Visually it is a horizontall stretched panel (UIStretch Horizontall for Background UISprite) with dynamic (dynamic news) text (UILabel with typewriter effect). All good, but text length can be a big and it is necessary his scroll the horizontally.

I read the article http://www.tasharen.com/?page_id=4444 and did the same. Everything is OK, but there are a couple of questions:

1. Since we have a dynamic text, we need (for dragging) to dynamically change the size of the collider, depending on the length of the text. How do I change the size of the collider, depending on the length of the text? Calculate collider.size <-> UILabel.text.Length.
2. I understand that I need to dynamically change the size (Stretch Clipped Panel horizontally) of the panel (Clipped Panel) because our "news panel" stretches?

Thanks!

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #1 on: March 20, 2013, 08:53:10 AM »
NGUITools.AddWidgetCollider overwrites the existing collider with a new one in the right size based on the widget.

I'm not sure I follow the second question. Set your panel to clip however wide you max want it to be? How does it stretch?

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #2 on: March 20, 2013, 09:18:36 AM »
See image in attach. Fiolet border - clipping area, orange border - label, gray - stretched background.
Need:
fiolet.size = gray.size - button.size - offset;
fiolet.x = button.x + button.width + offset;

Because background of news can stretch the width of the screen, and the clipping area of text should also be stretched, from its position on the blue button to the end of the screen.

Thanks!

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #3 on: March 20, 2013, 04:43:28 PM »
Ah, well the clipping area is exposed in UIPanel.clipRange (Vector 4: position xy, size zw) so you can just use the size of your stretched background there.


broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #4 on: March 21, 2013, 04:43:07 AM »
Yes, I tried to change UIPanel.clipRange with the Set method, but it doesn`t work. Then I tried to change UIPanel.clipRange by creating "new Vector4(x, y, z, w)" and it worked.
Now the size and position of the clipRange is calculated correctly based on the size and position of the background and button shift.
Code:

  1. public class NewsPanelManager : MonoBehaviour
  2. {
  3.         public UISlicedSprite stretchedBackground;
  4.         public UISlicedSprite expandButtonBackground;
  5.         public UIPanel textPanel;
  6.         public UILabel textLabel;
  7.        
  8.         private UIDraggablePanel draggableTextPanel;
  9.        
  10.         private Vector3 buttonScale;
  11.        
  12.         void Start()
  13.         {
  14.                 draggableTextPanel = textPanel.GetComponent<UIDraggablePanel>();
  15.                
  16.                 buttonScale = expandButtonBackground.transform.localScale;
  17.                
  18.                 UpdateLabelCollider();
  19.         }
  20.        
  21.         void Update()
  22.         {
  23.                 ResizeClippingArea();
  24.         }
  25.        
  26.         private void UpdateLabelCollider()
  27.         {
  28.                 NGUITools.AddWidgetCollider(textLabel.gameObject);
  29.         }
  30.        
  31.         private void ResizeClippingArea()
  32.         {
  33.                 Vector3 stretchedScale = stretchedBackground.transform.localScale;
  34.                
  35.                 float clippingSizeX = stretchedScale.x - buttonScale.x;
  36.                 float clippingSizeY = stretchedScale.y;
  37.                
  38.                 float clippingCenterX = (stretchedScale.x + buttonScale.x) * 0.5f;
  39.                 float clippingCenterY = 0f;
  40.                
  41.                 Vector4 clipRange = new Vector4(clippingCenterX, clippingCenterY, clippingSizeX, clippingSizeY);
  42.                 textPanel.clipRange = clipRange;
  43.                
  44.                 //draggableTextPanel.ResetPosition();
  45.         }
  46. }
  47.  

But now there are questions:
1. In Editor, depending on the angle scene rotation and length of the UILabel text you can see it or not. (Z order of panels?)
2. After I try to drag the label, it disappears sometimes. This is true even if I remove the code above.
3. When I drag the label and update clipRange of the panel (code above), the panel itself begins to shift.
4. What Grid settings (cell width, cell heigth) should be for such a case? Now is default.

See attach.

UPDATE:

1-2. Solved. Uhhhh. Set z to -1 on Clipping Panel.  :-[
3. Need help.
4. I think that these settings in this case do not matter.

Thanks!
« Last Edit: March 21, 2013, 07:52:42 AM by broken »

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #5 on: March 21, 2013, 01:41:43 PM »
I don`t understand why the clipped panel transform is moved while I change only clipRange  :-[

  1. public class NewsPanelManager : MonoBehaviour
  2. {
  3.         public UISlicedSprite stretchedBackground;
  4.     public UIPanel textPanel;
  5.     public UILabel textLabel;
  6.    
  7.     private UIDraggablePanel draggableTextPanel;
  8.  
  9.     void Start()
  10.     {
  11.         draggableTextPanel = textPanel.GetComponent<UIDraggablePanel>();
  12.        
  13.         UpdateLabelCollider();
  14.     }
  15.    
  16.     void Update()
  17.     {
  18.                 ResizeClippingArea();
  19.     }
  20.    
  21.     private void UpdateLabelCollider()
  22.     {
  23.         NGUITools.AddWidgetCollider(textLabel.gameObject);
  24.     }
  25.    
  26.     private void ResizeClippingArea()
  27.     {
  28.                 //draggableTextPanel.ResetPosition();
  29.                
  30.         Vector3 stretchedScale = stretchedBackground.transform.localScale;
  31.        
  32.         float clippingSizeX = stretchedScale.x;
  33.         float clippingSizeY = stretchedScale.y;
  34.        
  35.         float clippingCenterX = stretchedScale.x * 0.5f;
  36.         float clippingCenterY = 0f;
  37.        
  38.         Vector4 clipRange = new Vector4(clippingCenterX, clippingCenterY, clippingSizeX, clippingSizeY);
  39.         textPanel.clipRange = clipRange;
  40.                
  41.         Debug.Log(textPanel.clipRange);
  42.                
  43.         //draggableTextPanel.ResetPosition();
  44.     }
  45. }
  46.  

See attach.

Thanks!
« Last Edit: March 21, 2013, 02:05:15 PM by broken »

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #6 on: March 21, 2013, 06:19:41 PM »
I love the gif - very informative to do trouble shooting that way. :)

In answer to your questions
1) yes, the angle will some times put it behind the other sprite because of how unity determines distance from camera. That's why 3d GUI is recommended only to have a single material (atlas) for fonts and sprites, so that the depth setting determines which gets drawn first.
2) Well looks like you got it. Same thing as above. ;)

3) The way draggable panel works is by shifting the panel's transform.localposition and the clipping range opposite to each other, thus producing the effect that it stays in place while the content moves. If you are messing with one, but not realigning the other it will go "out of sync" and start moving.

4) From what I can see, you don't really need the grid in there. Do you use it to position something or do you just have a single big label? Just remove the grid and put the label in there directly.

Does that help you?

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #7 on: March 22, 2013, 01:03:10 AM »
Yes! Thanks!

3. I modified the code to this and everything works as it should:
  1.         private void ResizeClippingArea()
  2.         {
  3.                 Vector3 panelPosition = textPanel.transform.localPosition;
  4.                
  5.                 Vector3 stretchedScale = stretchedBackground.transform.localScale;
  6.                
  7.                 float clippingSizeX = stretchedScale.x - buttonScale.x;
  8.                 float clippingSizeY = stretchedScale.y;
  9.                
  10.                 float clippingCenterX = (stretchedScale.x + buttonScale.x) * 0.5f - panelPosition.x;
  11.                 float clippingCenterY = 0f;
  12.                
  13.                 Vector4 clipRange = new Vector4(clippingCenterX, clippingCenterY, clippingSizeX, clippingSizeY);
  14.                 textPanel.clipRange = clipRange;
  15.         }
  16.  

I added:
Vector3 panelPosition = textPanel.transform.localPosition;
and
float clippingCenterX = (stretchedScale.x + buttonScale.x) * 0.5f - panelPosition.x;

4. Yes, i have only one long label and therefore already deleted Grid as you advised.

To be continued :D

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #8 on: March 22, 2013, 07:59:14 AM »
How best to make automatic smooth scrolling UILabel content as soon as its width increases?

For example:
1. In the panel I have a UILabel with TypeWriter.
2. UILabel text length dynamically changes (Type Writer effect).
3. We have a Clipped Panel with known clipRange.
4. As soon as the width of the UILabel text exceeds the width of the clipRange.z, need to have the text smoothly shifted (scrolled) by a certain amount, so you can see the new print text.

We have:
0. Label scale
  1. Vector3 labelScale = textLabel.transform.localScale;
  2.  
1. Current Label Size (Type Writer part of text):
  1. Vector2 currentLabelSize = textLabel.font.CalculatePrintedSize(typeWriter.CurrentText, true, UIFont.SymbolStyle.None) * labelScale.x;
2. Full Label Size (Full text):
  1. Vector2 fullLabelSize = textLabel.font.CalculatePrintedSize(typeWriter.FullText, true, UIFont.SymbolStyle.None) * labelScale.x;
  2.  
3. Width of Panel clipRange:
  1. textPanel.clipRange.z;
  2.  
4. Scroll need flag:
  1. bool isScrolled = currentLabelSize.x > textPanel.clipRange.z;
  2.  

How best to implement automatic smooth scrolling?
1. With Scroll:
  1. textDraggablePanel.Scroll(delta)
  2.  
How calculate delta? For example one char shift.
2. With Tweeners or some other?

See attach. Need the same smooth scroll effect. In attached example I scroll with the mouse wheel.

Thanks!
« Last Edit: March 22, 2013, 02:07:02 PM by broken »

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #9 on: March 23, 2013, 08:38:49 AM »
Current result (see attach).

For scrolling:
  1. private IEnumerator ProcessScrollPanel()
  2. {
  3.         isScrolled = true;
  4.        
  5.         yield return new WaitForSeconds(0.1f);
  6.        
  7.         textDraggablePanel.Scroll(0.01f);
  8.        
  9.         isScrolled = false;
  10. }
  11.  

For stop scrolling:
  1. Vector3 labelScale = textLabel.transform.localScale;
  2.                                        
  3. Vector2 currentLabelSize = textLabel.font.CalculatePrintedSize(typeWriter.CurrentText, true, UIFont.SymbolStyle.None) * labelScale.x;
  4. Vector2 fullLabelSize = textLabel.font.CalculatePrintedSize(typeWriter.FullText, true, UIFont.SymbolStyle.None) * labelScale.x;
  5.  
  6. needScroll = (currentLabelSize.x > textPanel.clipRange.z);
  7.                        
  8. if (needScroll)
  9. {
  10.         bool stopScroll = Mathf.Abs(textPanel.transform.localPosition.x) + textPanel.clipRange.z >= fullLabelSize.x;
  11.        
  12.         if (!stopScroll)
  13.         {
  14.                 StartCoroutine(ProcessScrollPanel());
  15.         }
  16.         else
  17.         {
  18.                 needScroll = false;
  19.         }
  20. }
  21.  

There are other tips and ideas?

Thanks!

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #10 on: March 24, 2013, 01:59:13 AM »
Change Scroll() to SetDragAmount() and shift step.

Сhanged the code to the following:

  1. private IEnumerator ProcessScrollPanel()
  2. {
  3.         isScrolled = true;
  4.        
  5.         yield return new WaitForSeconds(0.1f);
  6.        
  7.         scrollShift += 0.01f;
  8.        
  9.         textDraggablePanel.SetDragAmount(scrollShift, 0.5f, false);
  10.        
  11.         isScrolled = false;
  12. }
  13.  

  1. if (!isScrolled)
  2. {
  3.         if (!scrollIsStart && typeWriter.Offset != 0f)
  4.         {
  5.                 Vector3 labelScale = textLabel.transform.localScale;
  6.                 Vector2 currentLabelSize = textLabel.font.CalculatePrintedSize(typeWriter.CurrentText, true, UIFont.SymbolStyle.None) * labelScale.x;
  7.                
  8.                 scrollIsStart = (currentLabelSize.x != 0 && currentLabelSize.x > textPanel.clipRange.z);
  9.         }
  10.                        
  11.         if (scrollIsStart)
  12.         {
  13.                 scrollIsComplete = scrollShift > 1f;
  14.                
  15.                 if (!scrollIsComplete)
  16.                 {
  17.                         StartCoroutine(ProcessScrollPanel());
  18.                 }
  19.         }
  20. }
  21.  

Now we need to figure out how to smoothly move the panel when the SetDragAmount shifted and how to know the current dragAmount while dragging the mouse to the panel again start scrolling with the current position, but it needs to change the shift value.

Any ideas?

Thanks!

broken

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 140
    • View Profile
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #11 on: March 24, 2013, 03:35:10 AM »
Change SetDragAmount to smooth moving UIPanel transform.position and clipRange with Lerp..

  1. private IEnumerator ProcessScrollPanel()
  2. {
  3.         Debug.Log("ProcessScrollPanel");
  4.                
  5.         isScrolled = true;
  6.                
  7.         float threshold = 0.01f;
  8.                
  9.         Vector3 beforeLocalPosition = textPanel.transform.localPosition;
  10.                
  11.         float beforeX = beforeLocalPosition.x;
  12.         float targetX = beforeX - 1f;
  13.         float afterX = beforeX;
  14.                
  15.         while (afterX != targetX)
  16.         {
  17.                 if (targetX - afterX <= threshold)
  18.                 {
  19.                         afterX = targetX;
  20.                 }
  21.                 else
  22.                 {
  23.                         afterX = NGUIMath.Lerp(beforeX, targetX, Time.deltaTime);
  24.                 }
  25.                        
  26.                 textPanel.transform.localPosition = new Vector3(afterX, beforeLocalPosition.y, beforeLocalPosition.z);
  27.        
  28.                 float offsetX = afterX - beforeX;
  29.                 Vector4 clipRange = textPanel.clipRange;
  30.                 clipRange.x -= offsetX;
  31.                 textPanel.clipRange = clipRange;
  32.  
  33.                 beforeX = afterX;
  34.  
  35.                 yield return null;
  36.         }
  37.  
  38.         isScrolled = false;
  39. }
  40.  

UPDATE:

No need Lerp here. Only small panel shift.

  1. private IEnumerator ProcessScrollPanel()
  2. {
  3.         Debug.Log("ProcessScrollPanel");
  4.                
  5.         isScrolled = true;
  6.                
  7.         Vector3 beforeLocalPosition = textPanel.transform.localPosition;
  8.                
  9.         float beforeX = beforeLocalPosition.x;
  10.         float targetX = beforeX - 0.5f;
  11.  
  12.         textPanel.transform.localPosition = new Vector3(targetX, beforeLocalPosition.y, beforeLocalPosition.z);
  13.        
  14.         float offsetX = targetX - beforeX;
  15.         Vector4 clipRange = textPanel.clipRange;
  16.         clipRange.x -= offsetX;
  17.         textPanel.clipRange = clipRange;
  18.  
  19.         isScrolled = false;
  20.                
  21.         yield return null;
  22. }
  23.  

How to calculate that the entire line has been scrolled and stop scrolling?

UPDATE:

First thing that comes to mind

  1. if (scrollIsStart)
  2. {
  3.         Vector2 fullLabelSize = textLabel.font.CalculatePrintedSize(typeWriter.FullText, true, UIFont.SymbolStyle.None) * labelScale.x;
  4.                                
  5.         Vector3 textPanelCurrentLocalPosition = textPanel.transform.localPosition;
  6.                                
  7.         float textPanelShift = Mathf.Abs(textPanelStartedLocalPosition.x - textPanelCurrentLocalPosition.x);
  8.                                
  9.         float softnessOffset = textPanel.clipSoftness.x * 2;
  10.                                
  11.         scrollIsComplete = textPanelShift + textPanel.clipRange.z - softnessOffset >= fullLabelSize.x;
  12.                                
  13.         if (!scrollIsComplete)
  14.         {
  15.                 StartCoroutine(ProcessScrollPanel());
  16.         }
  17. }
  18.  
« Last Edit: March 24, 2013, 05:20:34 AM by broken »

7toni7

  • Guest
Re: Scrollable (Draggable) Dynamic UILabel
« Reply #12 on: October 21, 2013, 04:14:45 AM »
Dear broken,

Could yo send to me the code for achieving this effect?
I would like to do it vertically. First, I need to know how to do it horizontally..
Best
Thanks!