Unity3D - Do we have a plugin or anyone have worked on Tag collection input view, see screenshot

早过忘川 提交于 2019-12-06 07:31:09
Fattie

Note! Before spending too much time on this answer, be sure to check out https://stackoverflow.com/a/38479097/294884


There is no existing good package for this. Butit is fairly easy to do this using Unity UI. You must familiarize yourself with HorizontalLayoutGroup, etc, and how to add UI items in code. Start from Unity tutorial. Enjoy!


I went ahead and made a demo project showing just how to do it.

The chain is like this: it has a depth of four

All Rows .. VerticalLayoutGroup, ContentSizeFitter
(EXPAND MUST BE "OFF")
(MUST BE HORIZONTAL >>UNCONSTRAINED<<, VERT PREFERRED)
 One Row ... HorizontalLayoutGroup, ContentSizeFitter  ** CFO OFF!
 (EXPAND MUST BE "OFF")
 (MUST BE HORIZONTAL PREFERRED, VERT PREFERRED)
  One Unit .... HorizontalLayoutGroup, ContentSizeFitter   **CFO ON!
  (EXPAND MUST BE "ON")
  (MUST BE HORIZONTAL PREFERRED, VERT PREFERRED)
    Text on the left (inherently sizes in Unity)
    The UI.Button ..... LayoutElement: choose and set "Min" Width/Height
      Text below button ...... nothing (probably won't need this)
 Another row...
 Another row...

 CFE means ChildForceExpand button, set correctly as shown!
 For all three ContentSizeFitters, select "Preferred" both ways

You have to carefully set all the items in the chain exactly like that. This is the art of autolayout in Unity! It does take a little while to get expert with it.

FULL DEMO PROJECT TO DOWNLOAD .... STATIC EXAMPLE:

http://speedy.sh/xcPcc/Teste.zip

Simply add and delete items or rows as you wish in the Editor to get started.


Next! What about reflowing the layout automatically, when you add/subtract items in code.

Here below is a FULL SCIPT which does just that.

Full demo project........

Click to download: http://speedy.sh/5XtkX/Teste2.zip

Launch the project. Go to the scene, actually hit Play.

Now while Play'ing, literally duplicate or delete either Items or whole Rows:

Then hit the "test" button to run Flow() ...

It will fix the layout flush left ...

Here's the script. It is absolutely straightforward - just attach it to the highest level (the level that holds "all the rows") and it figures everything out automatically.

// FattieFlow - flush left fitting for Unity reactive

// for simplicity, it does assume the only things under here
// are the relevant rows and items, and, the model row.

// NOTE ----
// this is deliberately programmed in the most illustrative manner.

// To use - just call Flow() any time to completely correct the layout.

// To put in a project: simply copy the "all rows" and the "model rows"
// in to your own scene.  That's it.

// To make your layout in editor. Just enable the model so you can see it.
// Just duplicate the model item/row a few times to see what you're doing.
// Change the colors/sizes/spacings in any way you wish.  Done.
// Eliminate the non-model items you used to layout.  Roll tide.

// To test.  Hit Play.  Literally add or delete "items" or rows,
// so that the flow is wrong.  Run the "Flow()" function and it
// will fix everything regardless.

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class FattieFlow:MonoBehaviour
    {
    public GameObject modelRow;
    public GameObject modelItem;


    void Awake()
        {
        modelRow.SetActive(false);
        modelItem.SetActive(false);
        // (it's a little untidy having the model (which is inactive)
        // sibling to the real rows, so just be careful with it...)
        modelRow.transform.SetAsFirstSibling();

        // simple example of how you might add an item
        Invoke("_teste", 2f);
        }

    void _teste()
        {
        ExampleAddItem("added this");
        Flow();
        }
    public void ExampleAddItem(string label)
        {
        if (transform.childCount < 2) _addARow();
        GameObject nu = Instantiate(modelItem);
        nu.name = "dynamically created item.";
        nu.transform.SetParent(transform.GetChild(1),false);
        nu.SetActive(true);
        Canvas.ForceUpdateCanvases();
        }

    float screen;

    public void Flow()
        {
        screen = GetComponent<RectTransform>().rect.width;

        // move downwards any which need to be moved downwards
        int row = 0;
        while (row < transform.childCount)  // (dynamic)
            {
            if (transform.GetChild(row).gameObject.activeSelf) FlowRow(row);
            ++row;
            }

        // move upwards any which can be moved upwards
        row = 0;
        while (row < transform.childCount)
            {
            if (transform.GetChild(row).gameObject.activeSelf) UnflowRow(row);
            ++row;
            }

        // account perfectly for spacing, regardless of the user's layout
        // (the most elegant algorithm is to simply ABA)
        row = 0;
        while (row < transform.childCount)  // (dynamic)
            {
            if (transform.GetChild(row).gameObject.activeSelf) FlowRow(row);
            ++row;
            }

        // remove any dud rows
        }

    private void UnflowRow(int r)
        {
        // so where possible move any from below us, into this row

        if (r == transform.childCount-1) return;
        Transform thisRow = transform.GetChild(r);
        Transform nextRow = transform.GetChild(r+1);

        while (_nominalWidthOfFirst(nextRow) < _availableSpaceOnRight(thisRow))
            {
            Transform moveMeUp = nextRow.GetChild(0);
            moveMeUp.SetParent(thisRow, false);
            moveMeUp.SetAsLastSibling();
            Canvas.ForceUpdateCanvases();
            }
        }

    private float _availableSpaceOnRight(Transform someRow)
        {
        return screen - someRow.GetComponent<RectTransform>().rect.width;
        }

    private float _nominalWidthOfFirst(Transform someRow)
        {
        if (someRow.childCount == 0) return screen*2f;
        return someRow.GetChild(0).GetComponent<RectTransform>().rect.width;
        }

    private void FlowRow(int r)
        {
        Transform row = transform.GetChild(r);

        // it's worth noting this is an indeterminate algorithm.
        // if you're not into compsci, don't worry about this. much.

        while (row.GetComponent<RectTransform>().rect.width > screen)
            {
            int k = row.childCount;

            if (k<1) return;    // setup problem!
            if (k==1) return;   // one item is too wide for screen!

            Transform lastOnThisRow = row.GetChild(k-1);
            MoveToStartOf( lastOnThisRow, r+1 );
            }
        }

    private void MoveToStartOf(Transform item, int newRow)
        {
        while (newRow >= transform.childCount)  // may have to add a row
            _addARow();

        Transform moveToThisRow = transform.GetChild(newRow);

        item.SetParent(moveToThisRow, false);
        item.SetAsFirstSibling();
        Canvas.ForceUpdateCanvases();
        }

    private void _addARow()
        {
        GameObject r = Instantiate(modelRow);
        r.name = "dynamically created row.";
        r.SetActive(true);
        r.transform.SetParent(transform,false);
        Canvas.ForceUpdateCanvases();
        // just remove the model unit
        while(r.transform.childCount>0)
            {
            Debug.Log("Deleting model");
            DestroyImmediate(r.transform.GetChild(0).gameObject);
            Canvas.ForceUpdateCanvases();
            }
        }
    }

The above package is a great tutorial on Unity.UI. But be sure to check out this fantastic QA: https://stackoverflow.com/a/38479097/294884

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!