Growing InputField list in Unity - c#

I need to implement input fields in unity which will be added on the fly as per the elements in a list. It should increase as per the objects present in a map "m_myClassMap".
Also, is it possible to fetch the position, layout settings ( i.e. x,y,z coordinates) of the existing Inputfields? I want these info to calculate the position of new inputfield.
For e.g.
List<InputField> inputFieldList = new List<InputField>();
foreach (MyClass myClassObj in m_myClassMap.Values)
{
// code below is just statement and is syntactically wrong
InputField newInputField = new InputField();
// Add properties like size or layout
// set the text
inputFieldList.Text = myClassObj.getInputBoxString();
inputFieldList.Add(newInputField );
}
I am not sure if its even possible..Any help will be welcome :)
Thanks!

The most robust thing to do here would be to use a layout group. This method plenty of well tested functionality.
Firstly add a a parent object. And add a Vertical Layout Group component to it. I've shown the hierarchy below by adding a Red panel to the blue panel. On the red panel is the Vertical Layout Group.
In this example I've used the inspector to manually add 4 input fields. Note the layout here is all automatic. I've included the settings on this particular input field below, you'll be able to experiment in the inspector and very quickly see what impact the various options have.
Now for your particular solution, you want to add the items programatically rather than through the inspector. For this you'll want to create a GameObject with a reference to the object holding the layout group.
Programatic Creation
The below code will add a list of prefabs to a class. (In this case the parent class should contain the Vertical Layout Group component)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LayoutGroupExample : MonoBehaviour {
public GameObject layoutObject;
public GameObject inputFieldPrefab;
void AddInputFields(){
var inputFieldList = new List<string>(){"First Name", "Last Name", "Email"};
foreach(var fieldName in inputFieldList){
GameObject go = GameObject.Instantiate(inputFieldPrefab);
go.name = fieldName;
go.transform.SetParent(layoutObject.transform);
var inputField = go.AddComponent<InputField>();
}
}
}
In the inspector assign the object containing the layout group to the layoutObject field.
Assign a prefab (which should be an Input Field object) to the inputFieldPrefab field)

Related

Transferring text of an input field to another input field on Unity

Im working on this Unity AR project and im trying to add a function where I can transfer text of an input field to another input field.
I have tried various scripts and have tried it on the app but the text of input field still cannot be transferred to another input field.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RemarksTransfer : MonoBehaviour
{
public string theRemarks;
public GameObject inputField;
public GameObject textDisplay;
public GameObject secondInput;
public void StoreRemarks()
{
theRemarks = inputField.GetComponent<Text>().text;
textDisplay.GetComponent<Text>().text = theRemarks;
if (textDisplay.TryGetComponent<InputField>(out var secondInput))
{
secondInput.text = theRemarks;
}
}
}
This is the code that I have used. However, this is for transferring text from an input field to a text box instead of another input field. Therefore, displaying the text only but not being able to edit on it.
Long story short, Im just trying to transfer text from an input field to another input field and the text can be edited if the user wants to edit.
What you’re seeing here is a GameObject that has an InputField. For an InputField to work correctly, it has an associated Text component. Your code is looking for the Text component. Now, if your second object DOES have an InputField component, search for that, and use its text property to get and set the text. You should also bring doing the same thing for your original InputField as well. As the Unity documentation says, the visible text shown might be truncated, or have asterisks if it’s a password. That’s what you’d get, instead of the actual underlying text value.
So, assuming your textDisplay has an InputField component, you could use:
if ( textDisplay.TryGetComponent<InputField>( out var secondInput ) )
{
secondInput.text = theRemarks;
}

How to detect clicks on a dynamically updated TextMeshProUI text?

I'm trying to implement a functionality that can determine which word in the text the user clicked on. To do this, I use the TextMeshProUGUI element and the following code:
using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro;
public class ExtraWordsDefinition : MonoBehaviour {
public TextMeshProUGUI text;
public string LastClickedWord;
void Start()
{
text = GetComponent<TextMeshProUGUI>();
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
var wordIndex = TMP_TextUtilities.FindIntersectingWord(text, Input.mousePosition, null);
if (wordIndex != -1)
{
LastClickedWord = text.textInfo.wordInfo[wordIndex].GetWord();
Debug.Log("Clicked on " + LastClickedWord);
}
}
}
}`
This code works fine if the text in the element is static (i.e.the text that I specified in the component's settings in the Unity inspector) then the words I click on are displayed in the console.
But, if I try to change the text of the component dynamically through the code, then the script stops detecting clicks on the text at all (the if condition does not work). Also, this way of changing text resets the text alignment settings.
At first I made code where the text was changed by assigning a new string to the ".text" property, but I also tried changing the text through the SetText() method, but that didn't change anything. Unfortunately, searching the internet didn't help me find an answer either.
Please help me figure out what is the reason.
First, I would add logs to verify that the mouse Vector and the TextMesh Vector are compatible. If that is the case, I would add a print when the test is updated and when the mouse is pressed to verify that the mouse pressing happens after the text has been updated and that the positions are still correct. I would also print the index to see if the text is actually found at the given position or if there is another problem. Also, ensure that nothing has a higher layer order than the text mesh after you change the text.

How to assign programmatically an Interactable Event in MRTK

I am creating a map in Unity3D to be displayed in Hololens 2. I am using MRTK to code interactable functionality.
Since the map contains a lot of independent countries, whose respond onClick may vary with time, I decided to add the required components programmatically. For example:
public Transform worlmap;
public Microsoft.MixedReality.Toolkit.UI.Theme mTheme;
public Microsoft.MixedReality.Toolkit.UI.States mStates;
List<Microsoft.MixedReality.Toolkit.UI.Theme> themes;
void Start()
{
themes = new List<Microsoft.MixedReality.Toolkit.UI.Theme>();
if (mTheme)
{
themes.Add(mTheme);
}
// Looping through all the countries in worldMap
foreach (Transform country in worldMap)
{
// Adding the 4 components which make a GameObject interactable in Hololens
country.gameObject.AddComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>();
country.gameObject.AddComponent<Microsoft.MixedReality.Toolkit.UI.PressableButton>();
country.gameObject.AddComponent<Microsoft.MixedReality.Toolkit.Input.NearInteractionTouchable>();
country.gameObject.AddComponent<MeshCollider>();
// Assigning State
country.gameObject.GetComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>().States = mStates;
// Assigning the Profiles (Will definine the colors based on the State)
Microsoft.MixedReality.Toolkit.UI.InteractableProfileItem mProfile = new Microsoft.MixedReality.Toolkit.UI.InteractableProfileItem();
mProfile.Themes = themes;
mProfile.Target = country.gameObject;
country.gameObject.GetComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>().Profiles.Add(mProfile);
// Assigning Events
// TODO
}
}
The part below is working, but I am not able to assign Events to the different countries in the same loop.
I can define these events in the Editor, for example:
But since it is a repetitive activity which may slightly change over time, I was trying to achieve the same programmatically inside the loop of the script above.
This is what I tried, but it is not working:
// Creating an Event
Microsoft.MixedReality.Toolkit.UI.InteractableEvent mEvent = new Microsoft.MixedReality.Toolkit.UI.InteractableEvent();
// Assigning the method to be executed during onClick
mEvent.Event.AddListener(country.gameObject.GetComponent<CountrySelected>().printName)
// Assigning the Event to Interactable
country.gameObject.GetComponent<Microsoft.MixedReality.Toolkit.UI.Interactable>().InteractableEvents.Add(mEvent);
What is the correct way of adding programmatically Events to an Interactable in MRTK?
To assign OnClick Event for the Interactable component at the runtime, please try the following code:
this.GetComponent<Interactable>().OnClick.AddListener(MyFun1);
The Interactable component profile in the Unity Editor may not display the new method at the runtime, but it does work in the scene.

How to Lock RectTransform's fields

I'm creating custom layout group and I want to control RectTransform on the child Objects. I want to lock some fields on child's RectTransform like when using canvas or Unity's Horizontal or Vertical group so that it cannot be modified.
I need the same effect. You can see this message on top of child's RectTransform : Some values driven by HorizontalLayoutGroup
I find a halfway :
Adding [ExecuteInEditMode] then:
public void Update()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
/* Todo => update child's positions here. */
}
#endif
}
Any other idea?
This is done with the DrivenRectTransformTracker API.
From the doc:
Driving a RectTransform means that the values of the driven
RectTransform are controlled by that component. These driven values
cannot be edited in the Inspector (they are shown as disabled). They
also won't be saved when saving a scene, which prevents undesired
scene file changes.
Whenever the component is changing values of driven RectTransforms, it
should first call the Clear method and then use the Add method to add
all RectTransforms it is driving. The Clear method should also be
called in the OnDisable callback of the component.
No example from the doc but below is how to use it:
public RectTransform targetRC;
UnityEngine.Object driver;
void Start()
{
DrivenRectTransformTracker dt = new DrivenRectTransformTracker();
dt.Clear();
//Object to drive the transform
driver = this;
dt.Add(driver, targetRC, DrivenTransformProperties.All);
}
The RectTransform linked to the targetRC variable will now be locked and cannot be modified from the Editor. It should now say something like "Some values are driven by another object". You can use DrivenTransformProperties to specify which variables to lock.
This is what it looks like after executing this code:

Unity compare if two input fields have same value

How can I achieve this? A function can take only 1 argument in Unity for an event.
There are two different input fields in the same canvas which I'd like to compare.
I'm assuming this can be done using object as argument but I don't know which object I can pass. I tried dragging the canvas and input field gameObject(I'm guessing that's what it's called) to the object parameter field of my selected function but they don't get accepted.
This is where I want to attach the script:-
InputFields are not GameObject. They are objects of UI.InputField class. So in your script import UI with
#using UnityEngine.UI;
Then create 2 InputField object.
public InputField inp1;
public InputField inp2;
then drag your InputFields to them. then you can compare their text like that:
if( inp1.text == inp2.text) {}
Edit: You shouldnt attach a script to there, because the variables may change dynamically. attach this script I have wroten to an empty game object, add new snippet on below to script, and then attach this empty game object to event field that you showed. Then you should select the function will be called when edit ended. For this, create two different function in script for each input field as:
//Call this on EndEdit for inputField1
public void InpField1EndEdit()
{
//compare input fields here or make what you want
}
//Call this on EndEdit for inputField2
public void InpField2EndEdit()
{
//compare input fields here or make what you want
}

Categories

Resources