- Home /
UI inputfield caret position wrong when midline alignment
When I set the vertical alignment of text in UI.inputfield as middle, the cursor (or caret) is still at the top of the text field. . I checked the InputField Input Caret object which is automatically instantiated in the playmode, but it has only Rect Transform component. To match the caret position to where text appears, I have to manually move the Inputfiedld Input Caret object during the play. I can't find a way to fix it before building the game.
I checked Unity answers, and similar issue (related to font size) was raised before and Unity said it's fixed in Unity4.5. But I am using the latest 4.6, and still have the problem.
Does anyone know how to fix this problem? Or is this a bug?
Thanks Misun
I'm having the same problem (Unity 5.0). Have you found an answer to this yet?
I have the same problem as well. Any idea what's going on?
Answer by az_ivan · Apr 25, 2015 at 02:40 PM
I solved the same problem. This is the structure of the input field game objects while being edited:
You need to change the pivot point Y value of the Text sub-game object:
It is depending on many factors. In my case a value of 1.2 centers the caret and text vertically.
GameObject goText = goEdit.transform.FindChild("Text").gameObject;
UnityEngine.UI.Text txt = goText.GetComponent<UnityEngine.UI.Text>();
txt.rectTransform.pivot = new Vector2(0, 1.2f);
The above code does the fix. goEdit is the game object of the input field.
I hope it will work for you too. Have fun! Ivan
Hey, this just solved an issue I was having with the input caret. Thank you very much for this quick fix.
thein - no kidding! BTW be careful that approach works good for all screen sizes, etc
This doesnt seem to work any more with Unity 5.2+. Now what works is to make the inner Text component be top aligned and then drag it's top border down a little from the top of the input box.
THIS WOR$$anonymous$$S EXTRE$$anonymous$$ELY WELL excuse the shouting, but people need to know. this is a problem all over forums.
Answer by Fattie · Jun 29, 2015 at 07:35 AM
Just another reason we are all
so happy to give Unity $4500 a license every two years
.
thanks Unity. You're so special.
OMG input field are unusable on the "new" lol UI. Say - who cares?
Here's a trivial solidish fix. Name script CaretStick, attach to each of your InputFields.
Just set the values (eg, 17, 2) appropriately for your look.
NB - I modified this from an earlier version (moving anchoredPosition so it works somewhat better on any screen size, rather than stupidly just Translate-ing, which is in world space).
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class CaretStick:MonoBehaviour, ISelectHandler
{
private bool alreadyFixed;
public float upp;
public float rightt;
public void OnSelect(BaseEventData eventData)
{
if (alreadyFixed) return;
alreadyFixed = true;
string nm = gameObject.name+" Input Caret";
RectTransform caretRT = (RectTransform)transform.Find(nm);
Vector2 fuckUnity = caretRT.anchoredPosition;
Debug.Log("here's the ap .. " +fuckUnity);
fuckUnity.y = fuckUnity.y + upp;
fuckUnity.x = fuckUnity.x + rightt;
caretRT.anchoredPosition = fuckUnity;
Debug.Log(" here's a somewhat better ap .. " +fuckUnity);
}
}
BTW if you're new to Unity you'll be saying "is this a joke, it does not handle a user resizing the window of the app". Well guess what: there's no resize window event in Unity. (No, really - they're just that lame. Just keep paying your $4500 per two years and suck, suck, suck it up.)
@Fattie dude you are guineas, hats off to you :)
and i really liked that variable name "fuckUnity" :D still laughing :D lol :D
LOL I really hope it helps. You know how it is I found some other code, fixed it up a bit and so on. "fuckUnity" should be a GLOBAL.
works great. thank you.
but there is an issue. i don't know if this is a general rule applied to all gameobjects or input field specific issue. when you add this script to object created from prefab it can't find caret object in OnSelect method. tried different ways to get reference to a caret object, but it still returns prefab child objects only.
ok. after some research i found out that on prefabs Caret object is added on the next frame. so i came up with something like this
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using System.Collections;
// on select event class
[System.Serializable]
public class OnSelectEvent : UnityEvent <BaseEventData> {}
// --
public class InputFieldAdditions : $$anonymous$$onoBehaviour, ISelectHandler
{
private bool alreadyFixed;
public float upFix = -9.0f;
public float rightFix;
public OnSelectEvent onSelectEvent;
public void Start ()
{
}
public void OnSelect (BaseEventData eventData)
{
if (onSelectEvent != null)
onSelectEvent.Invoke(eventData);
StartCoroutine(FixCaret());
}
IEnumerator FixCaret ()
{
if (alreadyFixed)
{
Debug.Log("fixed");
yield break;
}
string caretName = gameObject.name + " Input Caret";
RectTransform caretTransorm = null;
do
{
caretTransorm = (RectTransform)transform.Find (caretName);
Debug.Log("getting transform");
if (!caretTransorm)
yield return null;
} while (!caretTransorm);
Debug.Log("Fixing input field caret: " + caretName);
Vector2 caretPosition = caretTransorm.anchoredPosition;
caretPosition.x += rightFix;
caretPosition.y += upFix;
caretTransorm.anchoredPosition = caretPosition;
alreadyFixed = true;
}
}
Answer by Macrum · Jul 12, 2015 at 09:39 AM
I have tested this for a while now and I think I have a fix.
The caret starts to get off target if you scale your "Font". So when I setup my code I looked to see if a standard ratio would compensate for changes in font size.
The formula I finished with is:
caret.posY = caret.posY + ((font.Size - (Working Font Size)) * "Scale Ratio")
Arial Values: "Working Font Size" = 14 "Scale Ratio" = 0.84
Here is the script that uses it:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
// Purpose: Reposition the "caret" when using "InputField"
// Use: Add as component to each "Input Field" object
// Made for Unity Version 5.1.1
public class CaretManage : MonoBehaviour {
//Controls access to the subset of 'IF' statements
private bool control1 = false;
//Controls access to the first step
private bool control2 = false;
//Controls access to the second step
private bool control3 = false;
/// <summary>
/// Font setting where the caret aligns naturally.
/// Default: 14 (Arial)
/// </summary>
public int workingFontSize = 14;
/// <summary>
/// The ratio used to move the caret relative to the font size.
/// Default: 0.84 (Arial)
/// </summary>
public float ratioToFont = 0.84f;
//Update Method
void Update(){
if (control1 == false) {
if (control2 == false) {
InputField temp = gameObject.GetComponent<InputField> ();
//Causes the "InputField" to create the "Caret Object'
temp.text = "1";
temp.text = "";
control2 = true;
} else if (control3 == false) {
ResetCaret ();
control3 = true;
control1 = true;
}
}
}
/// <summary>
/// Resets the caret.
/// Accesses the "Local Position" of the caret Object
/// and changes the "Y Value" based on the formula in
/// the "ScaleCaret()" method
/// </summary>
public void ResetCaret(){
string name = gameObject.name + " Input Caret";
Transform temp1 = gameObject.transform;
GameObject temp2 = temp1.Find (name).gameObject;
Vector3 temp3 = temp2.transform.localPosition;
temp3.y = temp3.y + ScaleCaret();
temp2.transform.localPosition = temp3;
}
/// <summary>
/// Uses the "workingFontSize" and "ratioToFont to
/// generate a float value to correct the loaction
/// of the "Input Field" caret.
/// </summary>
/// <returns>New float to add to the Y pos of the caret.</returns>
private float ScaleCaret(){
InputField temp1 = gameObject.GetComponent<InputField> ();
Text temp2 = temp1.textComponent;
int temp3 = temp2.fontSize;
float temp4 = (float)(temp3 - workingFontSize) * (ratioToFont);
return temp4;
}
}
Hope this helps. Please let me know if you find any places where the code fails and I will try again.
I haven't had a chance to test this, but impressive thinking!
Answer by Streamfall · Sep 17, 2015 at 03:41 PM
Hey guys,
I guess I found a fix. It will likely not work in all cases.
If you go to the import settings for your font, set the font size equal to that of your Text component. Apparently the caret position is calculated based on that import setting.
Having done that, my positioning is correct.
If you have multiple size requirements for your font, it may be necessary to create multiple fonts at different sizes.
In my case the font size in the font file was the same as the Text in the input field, but the Ascent Calculation $$anonymous$$ode was set to "Legacy version 2 mode (glyph bounding boxes)", I change it to "Face ascender metric" and voilà! Fixed! I had to restart the game after applying the change to the file, so the position of the caret would be recalculated, of course. I'm using Unity 5.4.1f1. I$$anonymous$$O you should try this before anything else, this is a way more elegant solution then adding one more "one-issue-scripts".
Answer by Ox_ · Jun 24, 2015 at 10:45 AM
Here's an ugly hack because the solution above is not working for me:
public InputField input;
bool _previouslyFocused;
void OnEnable()
{
_previouslyFocused = false;
}
void Update()
{
if (input.isFocused == false)
_previouslyFocused = false;
else if (_previouslyFocused == false)
{
_previouslyFocused = true;
RectTransform[] children = input.GetComponentsInChildren<RectTransform>();
foreach (var item in children)
{
if (item == input.gameObject.GetComponent<RectTransform>())
continue;
if (item.gameObject.GetComponent<Text>() == null)
{
item.pivot = new Vector2(0.5f, 0.8f);
}
}
}
}