2

I need a Unity plugin with following features (like Android Chips):

User will search the tags from a list and selected item from list will be shown as a tag. Tag will have text with a cross. Mobile device width will be the maximum horizontal space and if its full, next tag will go in next line.

enter image description here

Fattie
  • 27,874
  • 70
  • 431
  • 719
Syed Asad Ali
  • 1,308
  • 1
  • 9
  • 14
  • 1
    Important! My answer below which **manipulates rows** is fine but check this out: http://stackoverflow.com/a/38479097/294884 – Fattie Jul 20 '16 at 14:05

1 Answers1

3

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.

enter image description here

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:

enter image description here

enter image description here

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

enter image description here

It will fix the layout flush left ...

enter image description here

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

Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • thanks for all the explanation and even for the linked unity project. I am trying to get all these in few hours. – Syed Asad Ali Jul 13 '16 at 07:07
  • I am able to add new items easily and then call Flow() to adjust the layout. It just doesn't overflow when the new item exceeds little bit of space. – Syed Asad Ali Jul 13 '16 at 12:22
  • I worked out to access the title of chip(model unit) and remove it on its cross button. I added a script on the chip and wrote its click event there. called Destroy(this) to remove it and also I have make a reference of FattieFlow scrpit from "all rows" game object. After Destroy(this), I call Flow(). Removing chips still have some problems. – Syed Asad Ali Jul 13 '16 at 12:33
  • Works going great!! Now I am trying my luck on removing chips on their X button using same way as in my previous comment. – Syed Asad Ali Jul 14 '16 at 06:55
  • hi @Joe Blow - please look into this( https://www.dropbox.com/sh/59o7izgrz4ziuuk/AACrL3PGTXeH_6hSew-yFhVta?dl=0 ) . I have made some changes in your second project according my need. Changes are: -deleted all static rows -Random titles of chips -Chips remove by their X button -New chip is created as the last item of the last row – Syed Asad Ali Jul 14 '16 at 09:54
  • I am facing two issues in above project: - Some chips exceed row bound when creating them( https://www.dropbox.com/s/ze36nkx1e162hku/Screen%20Shot%202016-07-14%20at%201.00.24%20PM.png?dl=0 ) - When removing with X button, some chip does not adjust layout to move up ( https://www.dropbox.com/s/ago4n88wcb3kiut/Screen%20Shot%202016-07-14%20at%202.48.47%20PM.png?dl=0 ) – Syed Asad Ali Jul 14 '16 at 10:04
  • 1
    hi @SyedAsadAli ! More good news, check out this question I posed and **the answer here** ............... http://stackoverflow.com/a/38479097/294884 – Fattie Jul 20 '16 at 14:04