Search Unity

[RELEASED] Dynamic Panels - draggable, resizable, dockable and stackable UI panels

Discussion in 'Assets and Asset Store' started by yasirkula, Mar 22, 2018.

  1. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    can you post a simple demo like my needs,
     
  2. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I'm sorry but I can't. I have other projects that I need to focus.
     
  3. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Is there any way available to independently use PanelResizeHelper class on my panel ?
     
  4. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    It is somewhat tightly coupled with other DynamicPanels classes and functions. I don't think you can use that class on its own without greatly refactoring the code.
     
  5. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Okay, but even i tried to used it with Dynamic Panel canvas my panel is not resizing. Remember this is my hierarchy
    1. Canvas
    1.1. Image (Dynamic Panel canvas attached)
    1.1.1Raw Image with render texture.
     
  6. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You have to make your panel a child of DynamicPanelsCanvas (1.1) and then add the panel to DynamicPanelsCanvas' "= Free Panels =" list so that it becomes an actual Panel when the game starts. Then the system will add PanelResizeHelper objects to the panel's all 4 edges automatically.

    You can't use PanelResizeHelper without this setup, as I said it will require moderate code refactoring.
     
  7. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Thanks, it worked after adding one more parent panel with DynamicPanelsCanvas. But still, there are some problems. I tried to understand the documentation on github page but it is not enough or too difficult for me.
    1. When i play, the panel gets resize and takes the full width of the parent panel. Even, I have given the initial size and min size into docked panels. I am using dock panel the panel should dock but able to resize from top and right.
    2. Is there any way available to not instantiate the header. I don't want header.
     
  8. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    1. Docked panels behave similar to Unity's panels (e.g. Inspector, Hierarchy). In Unity, try closing all panels and leave only 2 panels that are docked side by side. You can resize only horizontally, not vertically. If you want to resize in all directions, then the panel must be a free panel.
    2. You can modify DynamicPanel prefab in Resources folder but make sure to set the Panel's Header Height property to 0. You may need to modify the DynamicPanelTab prefab, as well.

    If you just want resizable panels and nothing more, I think DynamicPanels is an overkill. You can find example code snippets for resizable panels online; for example: https://assetstore.unity.com/packages/essentials/unity-samples-ui-25468
     
  9. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    can you answer my some question?

    1、i want to modify the panel tab size,can you give some method
    2、can i insert some controls like text button to the panel header

    i hope you can give me some method to solve my problems
     
  10. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can modify the DynamicPanel (for 1, 2) and DynamicPanelTab (for 1) prefabs. If you change the height of the panel's header in DynamicPanel prefab, make sure to update its Header Height property, as well.
     
  11. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    Is there any way available to insert text control or button control to the panels header
     
  12. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Panel's header is part of DynamicPanel prefab. You must modify it, i.e. create the Text/Button child object inside its header.
     
  13. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    thank you!

    and i want to achieve an effect,like i drag the panel tab but it does not drag to the another canvas,then it will back to the original position
     
  14. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    can you give me some method ?
     
  15. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    sorry ,i have another problem ,the panel header's height can be equal to the panel tab's height?

    i have changed some times,but the panel tab's height can not be equal to the header's height。
     
  16. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can change PanelManager.OnEndPanelTabTranslate as follows:
    Code (CSharp):
    1. if( draggedPanel == panelTab.Panel )
    2. {
    3.     if( previewPanel.parent == panelTab.Panel.Canvas.RectTransform )
    4.     {
    5.         CancelDraggingPanel();
    6.         return;
    7.     }
    8.  
    9.     ...
    10. }
    To change tabs' height, apparently you need to modify DynamicPanel.PanelHeader.HorizontalLayoutGroup's Padding.
     
  17. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    sorry,i have asked so many problems,but i have new problem。
    i can insert the text control to the panel header successfully,but the text position is after the panel tab,but i want the text position is before the panel tab,can you give some advice
     
  18. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can try adding this script to your Text:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class AlwaysFirstSibling : MonoBehaviour
    4. {
    5.     void LateUpdate()
    6.     {
    7.         if( transform.GetSiblingIndex() > 0 )
    8.             transform.SetAsFirstSibling();
    9.     }
    10. }
     
  19. AlexYao762

    AlexYao762

    Joined:
    Aug 27, 2020
    Posts:
    4
    on the basis of xpzhang's problem,
    if i want to add text control on the far left of the panel header,add a button on the far right of the panel header,what shall i do?
     
  20. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    now each panel tab's size is the same,is there any way available to make each panel tab different in size
     
  21. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    @AlexYao762 You need to put these objects inside DynamicPanel.PanelHeader prefab object. Add the above script to the Text and add another script (that calls
    transform.SetAsLastSibling();
    inside LateUpdate) to the button.

    @xpzhang PanelTab prefab's LayoutElement component and DynamicPanel.PanelHeader's HorizontalLayoutGroup components (these are all Unity's built-in components) handle the tab sizing. You need to tinker with them.
     
  22. AlexYao762

    AlexYao762

    Joined:
    Aug 27, 2020
    Posts:
    4
    I've tried you method,but the newly added button is not on the far rigth of the panel header ,it is just after the last panel tab
     
  23. AlexYao762

    AlexYao762

    Joined:
    Aug 27, 2020
    Posts:
    4
    maybe i didn't make my problem clear

    i want to insert the button on the far right edge,not next to the panel tab
     
  24. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    can you tell me where is the code about adding the panel tab,and the code about setting the panel'stab size
     
  25. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    @AlexYao762 Hmm, you can increase DynamicPanel.PanelHeader's Padding Right property, add a Layout Element component to your button and then set its Ignore Layout property to true. Finally, you can remove the SetAsLastSibling script from the button (it is no longer necessary) and anchor it to the right edge of the PanelHeader.

    @xpzhang There is no script. The Unity components I've mentioned calculate the tabs' sizes.
     
  26. AlexYao762

    AlexYao762

    Joined:
    Aug 27, 2020
    Posts:
    4
    Ťhank you for your help
     
    yasirkula likes this.
  27. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    I have a new problem,i have insert some controls in my panel,but when i run the project,those controls's position have changed,can you tell what happened,and how can i solve the problem。
     
  28. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I need to see your controls in the Hierarchy and also see their Inspectors.
     
  29. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    in particular,the top and the bottom controls will be out of the display area or cover by the panel header
     
  30. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    I have solved this problem maybe,
    I changed some controls's anchor point,and it has displayed normally。
    thank you for your help,perhaps it will appear later,and I hope you can help me
     
  31. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    I have a new problem,
    Premise,the tab1 has a video control .i switch between two tabs,i can't make the tab unactive.
    when i switch the tab1 to tab2,i want to pause the video.
    how can i realize this function.
     
  32. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can try changing this line as follows:
    Code (CSharp):
    1. //Content.gameObject.SetActive( activeState );
    2. if( activeState )
    3.     Content.SetAsLastSibling();
     
    Last edited: Sep 4, 2020
  33. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    maybe this only change the panel display order.but i want to do some operation when change the panel tab
     
  34. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can register to
    DynamicPanels.PanelNotificationCenter.OnActiveTabChanged
    event. This event takes a PanelTab parameter and this parameter has a Content property. This is the root Transform of your panel content that is associated to that tab. You can use this event to execute your logic.

    To also execute some logic for the tabs that became inactive, you can access to PanelTab's Panel property in OnActiveTabChanged and iterate over its tabs. Then, execute the inactive logic for the tabs that aren't equal to the tab that became active.
     
  35. xpzhang

    xpzhang

    Joined:
    Jul 23, 2020
    Posts:
    17
    when i drag the panel to the new canvas,how can make it fit the new canvas size,in other words,make it maximize
     
  36. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can modify PanelManager.OnEndPanelTranslate's nested if condition as follows:
    Code (CSharp):
    1. if( draggedPanel.RectTransform.parent != draggedPanel.Canvas.RectTransform )
    2. {
    3.     draggedPanel.RectTransform.parent.GetComponent<DynamicPanelsCanvas>().UnanchoredPanelGroup.AddElement( draggedPanel );
    4.     draggedPanel.RectTransform.anchoredPosition = Vector2.zero;
    5.     draggedPanel.RectTransform.sizeDelta = ( (RectTransform) draggedPanel.RectTransform.parent ).rect.size;
    6. }
    And replace PanelManager.OnEndPanelTabTranslate's
    detachedPanel.MoveTo( draggingPointer.position );
    line as follows:
    Code (CSharp):
    1. detachedPanel.RectTransform.anchoredPosition = Vector2.zero;
    2. detachedPanel.RectTransform.sizeDelta = previewPanelCanvas.RectTransform.rect.size;
    These functions inside PanelManager already have meaningful names. Please try modifying the source code yourself first, instead of asking me to do it for you every time.
     
  37. appminded

    appminded

    Joined:
    Nov 27, 2014
    Posts:
    7
    great Asset!
    how can I implement a resize tab event?
    something like

    static event TabDelegate OnStartedResizeTab
    static event TabDelegate OnStoppedResizeTab

    thanks
     
  38. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can add public static events to PanelResizeHelper.cs and call these events in the OnBeginDrag and OnEndDrag functions.
     
    appminded likes this.
  39. appminded

    appminded

    Joined:
    Nov 27, 2014
    Posts:
    7
    thanks, it works!
     
    yasirkula likes this.
  40. Gekigengar

    Gekigengar

    Joined:
    Jan 20, 2013
    Posts:
    738
    Tab.png
    I changed the size of tabs in the prefabs, but the tab size preview does not change.
    This should follow the prefab's tab size.
     
  41. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You may have missed this note:
     
  42. Gekigengar

    Gekigengar

    Joined:
    Jan 20, 2013
    Posts:
    738
    You're right, thanks!

    Though, is there a reason not to keep that update with the prefab instead?
     
  43. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    There is a gap between the top edge of the panel and the top edge of the tabs. This gap is included in Header Height but I can't determine this height from code. I have access to the tabs' height value but not that gap value.
     
  44. Gekigengar

    Gekigengar

    Joined:
    Jan 20, 2013
    Posts:
    738
    Hey there, I am using Events to update my panel.
    This is what I usually have in my UI script.
    Code (CSharp):
    1.  
    2.         void OnEnable()
    3.         {
    4.             ChangeEventSubscription(true);
    5.         }
    6.      
    7.         void OnDisable()
    8.         {
    9.             ChangeEventSubscription(false);
    10.         }
    11.      
    12.         private void ChangeEventSubscription(bool state)
    13.         {
    14.             if (state)
    15.             {
    16.                 PlayerController.OnSomethingViewChange += OnNewViewDataReceived;
    17.             }
    18.             else
    19.             {
    20.                 PlayerController.OnSomethingViewChange-= OnNewViewDataReceived;
    21.             }
    22.         }
    23.  
    And then I call this from Player Controller when Data has changed.

    Code (CSharp):
    1. OnSomethingViewChange ?.Invoke(ViewData);
    But unfortunately, the UI is disabled when placed within a tab, thus unsubscribing and missing all important events while behind a tab.
    I was hoping there is an option to hide canvas render instead of disabling the UI?
     
  45. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You have to modify PanelTab.cs to achieve this. Basically, you want to attach a CanvasGroup component to Content (if it doesn't already exist) in Initialize function and then, inside SetActive, instead of changing Content.gameObject.SetActive, you'd want to change the CanvasGroup's alpha and blocksRaycasts properties accordingly.
     
  46. Gekigengar

    Gekigengar

    Joined:
    Jan 20, 2013
    Posts:
    738
    Added this
    Code (CSharp):
    1.         private CanvasGroup m_contentCanvasGroup;
    2.        
    3.         private CanvasGroup ContentCanvasGroup
    4.         {
    5.             get
    6.             {
    7.                 if (!m_contentCanvasGroup)
    8.                 {
    9.                     m_contentCanvasGroup = GetComponent<CanvasGroup>();
    10.                     if (!m_contentCanvasGroup)
    11.                     {
    12.                         m_contentCanvasGroup = Content.gameObject.AddComponent<CanvasGroup>();
    13.                     }
    14.                 }
    15.                 return m_contentCanvasGroup;
    16.             }
    17.         }
    Edited this
    Code (CSharp):
    1.         private void SetActive( bool activeState )
    2.         {
    3.             if( !Content )
    4.                 m_panel.Internal.RemoveTab( m_panel.GetTabIndex( this ), true );
    5.             else
    6.             {
    7.                 if( activeState )
    8.                 {
    9.                     background.color = m_panel.TabSelectedColor;
    10.                     nameHolder.color = m_panel.TabSelectedTextColor;
    11.                 }
    12.                 else
    13.                 {
    14.                     background.color = m_panel.TabNormalColor;
    15.                     nameHolder.color = m_panel.TabNormalTextColor;
    16.                 }
    17.                
    18.                 // Reduce alpha instead of SetActive state
    19.                 //Content.gameObject.SetActive( activeState );
    20.                 ContentCanvasGroup.alpha = activeState ? 1 : 0;
    21.                 ContentCanvasGroup.blocksRaycasts = activeState;
    22.             }
    23.         }
    Works perfectly! Thanks!
     
    yasirkula likes this.
  47. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    In your first code,
    m_contentCanvasGroup = GetComponent<CanvasGroup>();
    should be
    m_contentCanvasGroup = Content.GetComponent<CanvasGroup>();
    . Other than that, your code seems solid.
     
    Gekigengar likes this.
  48. Gekigengar

    Gekigengar

    Joined:
    Jan 20, 2013
    Posts:
    738
    Whoops, I missed that, thanks!
     
  49. swProdBdk

    swProdBdk

    Joined:
    Apr 22, 2020
    Posts:
    10
    I get several NullReferenceExceptions when using this together with Unity "Script Changes While Playing - setting --> Recompile and Continue Playing.
    Happens when the game recompiles and continues playing. So I guess something in the panel management lifecycle is not ready for this sort of reboot.

    Anyone else who has encountered this, and knows a solutions other than not using 'recompile and continue playing'?

    NullReferenceException: Object reference not set to an instance of an object
    DynamicPanels.Panel.OnEnable () (at Assets/Plugins/DynamicPanels/Scripts/Panel.cs:354)

    NullReferenceException: Object reference not set to an instance of an object
    DynamicPanels.PanelManager.Update () (at Assets/Plugins/DynamicPanels/Scripts/PanelManager.cs:90)


    NullReferenceException: Object reference not set to an instance of an object
    Com.TheFallenGames.OSA.Core.OSA`2[TParams,TItemViewsHolder].MyUpdate () (at Assets/Plugins/Com.TheFallenGames/OSA/Scripts/Core/OSAInternal.cs:1478)
    Com.TheFallenGames.OSA.Core.OSA`2[TParams,TItemViewsHolder].Update () (at Assets/Plugins/Com.TheFallenGames/OSA/Scripts/Core/OSA.cs:154)
    Com.TheFallenGames.OSA.CustomAdapters.TableView.Tuple.TupleAdapter`2[TParams,TTupleValueViewsHolder].Update () (at Assets/Plugins/Com.TheFallenGames/OSA/Scripts/CustomAdapters/TableView/Tuple/TupleAdapter.cs:74)

    NullReferenceException: Object reference not set to an instance of an object
    Com.TheFallenGames.OSA.Core.OSA`2[TParams,TItemViewsHolder].MyLateUpdate () (at Assets/Plugins/Com.TheFallenGames/OSA/Scripts/Core/OSAInternal.cs:1588)
    Com.TheFallenGames.OSA.Core.OSA`2[TParams,TItemViewsHolder].LateUpdate () (at Assets/Plugins/Com.TheFallenGames/OSA/Scripts/Core/OSA.cs:155)

    NullReferenceException: Object reference not set to an instance of an object
    DynamicPanels.PanelManager.CancelDraggingPanel () (at Assets/Plugins/DynamicPanels/Scripts/PanelManager.cs:315)
    DynamicPanels.PanelManager.StopCanvasOperations (DynamicPanels.DynamicPanelsCanvas canvas) (at Assets/Plugins/DynamicPanels/Scripts/PanelManager.cs:302)
    DynamicPanels.DynamicPanelsCanvas.LateUpdate () (at Assets/Plugins/DynamicPanels/Scripts/DynamicPanelsCanvas
     
  50. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I don't recommend using Recompile and Continue Playing because it resets static variables after recompile and probably non-serializable fields, as well (e.g. dictionaries). It is impossible to resolve this issue. I honestly don't recommend Recompile and Continue Playing in any Unity project unless you have a single script that rotates a cube.