c# Xamarin UITextField setting the cursor position - c#

I need to position the cursor of a UITextField in the exact same position as another previous text field. I get the position of the cursor in the first text field as nint index = txtToField.GetOffsetFromPosition(txtToField.BeginningOfDocument, txtToField.SelectedTextRange.Start);, which correctly gets the number of characters from the beginning of the textfield my cursor is currently in. After some research, and using the question below:
Setting cursor position of UITextField
I have tried to implement the question's solution to setting the cursor position in a textfield, using the index I previously got. This doesn't work, and after making the text field the first responder and running:
txtTo.BecomeFirstResponder();
UITextPosition positionSet = txtTo.GetPosition(txtTo.BeginningOfDocument, position);
txtTo.SelectedTextRange = txtTo.GetTextRange(positionSet, positionSet);
It automatically puts your cursor at the end of the UITextField. Further, I attempted to check if the SelectedTextRange method worked as expected, however when trying to set all of the text in the text field as selected:
txtTo.BecomeFirstResponder();
txtTo.SelectedTextRange = txtTo.GetTextRange(txtTo.BeginningOfDocument, txtTo.EndOfDocument);
It also automatically puts the cursor to the end of the UITextField, which is a standard behaviour for BecomeFirstResponder(). Does SelectedTextRange not work in this current version of Xamarin?
I am using version 7.6.10 (build 27) of Xamarin and Xamarin.iOS version 12.0.0.15.

Cause:
The cursor is at the end of the text in dafault.When you init a UITextField and set it as FirstResponder in the method ViewDidLoad.The view is still not finish init.
Solution:
You can call these method in the method EditingStarted .And don't forget set the delegate.
public partial clas xxxViewController:UIViewController,IUITextFieldDelegate
txtTo.WeakDelegate=this;
[Export("textFieldDidBeginEditing:")]
public void EditingStarted(UITextField textField)
{
NSRange range = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, range.Location);
UITextPosition end = textField.GetPosition(start, range.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}
If you do want to call them in ViewDidLoad .You can set a delay (for example 0.1s).
//...
this.PerformSelector(new Selector("MoveCursorPosition:"),txtTo,0.1);
//...
[Export("MoveCursorPosition:")]
public void MoveCursorPosition(UITextField textField)
{
NSRange range = new NSRange(index, 0);
UITextPosition start = textField.GetPosition(textField.BeginningOfDocument, range.Location);
UITextPosition end = textField.GetPosition(start, range.Length);
textField.SelectedTextRange = textField.GetTextRange(start, end);
}

Related

Can you get the final value from an animation before that animation has completed?

Say I start a four-second DoubleAnimation on the Canvas.Left property of a control that animates the value from its current value to 100 and that animation was started by calling BeginAnimation on that control in code-behind.
void Animate(Control someControlOnCanvas, int newX){
var canvasLeftAnimation = new DoubleAnimation();
canvasLeftAnimation.To = newX;
canvasLeftAnimation.FillBehavior = FillBehavior.Stop;
canvasLeftAnimation.Duration = new Duration(TimeSpan.FromSeconds(4));
canvasLeftAnimation.Completed += (s, e) => {
Canvas.SetLeft(targetButton, x);
};
someControlOnCanvas.BeginAnimation(Canvas.LeftProperty, canvasLeftAnimation);
}
Animate(somethingToMove, 100);
Say half-way through that animation--at the two-second mark--I need to cancel the current animation and start a new one with a new To position (the From position would be wherever it is right now) that's 100 past where the first animation would end (i.e. not where it currently is at 50, but where it's supposed to be, which is 100, so adding another 100 would yield a new target of 200.)
If I try getting the current Left value, it's the animated value of 50. If I try getting the base value, it's where the animation started, which is zero since it's not officially updated until the completion handler fires.
So outside of manually adding a variable to track where things should be, how can I start a new animation that says 'Go to the original end, plus 100?'
My thoughts are:
Get the existing/current animation
Get it's To value
Start a new animation with the previous animation's To value, plus 100
What I'm stuck on is getting #1.
...or am I going about this all wrong?

How can I display an element relative to an other in Unity without "moving effects"?

I'm starting with unity since a few weeks and i'm stuck with some displaying problems.
You can see what I want to achieve here :
On several of my pages I have a title with an icon on the left and I want it to be at 40px on the left of the title, no matter the size of it.
So I did a prefab with an empty Text for the title, an empty RawImage for the icon and I put that prefab on the center top of the screen.
I link the following C# script on my prefab with the 'string' parameter for the title and the 'Texture' parameter for the icon to display.
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
public class TitlePage : MonoBehaviour {
public string title;
public Texture texture;
private Text titlePageText;
private RawImage iconPage;
void Awake()
{
titlePageText = gameObject.GetComponentsInChildren<Text>().First();
iconPage = gameObject.GetComponentsInChildren<RawImage>().First();
}
void Start()
{
titlePageText.text = title;
}
void Update()
{
iconPage.rectTransform.anchoredPosition = new Vector2(-titlePageText.rectTransform.rect.width / 2 - 40, iconPage.rectTransform.anchoredPosition.y);
iconPage.texture = texture;
}
}
The title is set well in the "Start" function, the problem is with the icon. The code in the "Update" function put the icon at the wanted position if it's in the "Update" function because in the "Start", 'titlePageText.rectTransform.rect.width' give 0. But with that code in the "Update" function, the icon start with a display by default in the center and nearly instantly it moves on the left but we can see that position changing.
Maybe there's a solution to avoid that ?
Maybe I started in a wrong way ?
(I don't put my title's text hardly because I want my application to be multilingual so instead of displaying the 'string' in parameter, I'll display the corresponding translation and it's why I can't set a fixed position because two translations are not the same length.)
Thanks in advance !
I am not entirely sure what your problem is exactly, but it does sound like you are trying to solve something from a slightly awkward angle. IS there a reason for not using Unity's layout (or even auto layout groups) to achieve your goal?
I just did a quick test: added 'Content Size Fitter component' to the text object with Horizontal set to Preferred, then placed an image as a child of that text object, when I set the anchor X to 0 and pivot X to 1, the image now follows the left hand side of the text, no matter what size.
This has the advantage of doing absolutely zero work unless text (or its position) changes, in which case everything is handled automagically by Unity's UI system
It sounds like the width of the titlePageText is not obtaining a value immediately in Start(), which is why it is initially zero. After a couple of frames when a non-zero value is found, it finally shifts your iconPage over but your object already has a texture at this point. You really shouldn't be doing this in Update() because it means it will constantly be setting the anchoredPosition and texture of your iconPage every frame.
One solution to avoid this would be to use a coroutine with yield to wait for your components to initialize and then set the position. Note that this is a bit of a hack since you are introducing some forced loading time.
public string title;
public Texture texture;
private Text titlePageText;
private RawImage iconPage;
void Awake()
{
titlePageText = gameObject.GetComponentsInChildren<Text>().First();
iconPage = gameObject.GetComponentsInChildren<RawImage>().First();
}
void Start()
{
titlePageText.text = title;
StartCoroutine(initializeComponenets());
}
IEnumerator initializeComponenets()
{
yield return new waitForSeconds(.05f); //might need longer wait here
iconPage.rectTransform.anchoredPosition = new Vector2(-titlePageText.rectTransform.rect.width / 2 - 40, iconPage.rectTransform.anchoredPosition.y);
iconPage.texture = texture;
}

How to create a smooth animated text marquee?

I know that there are lot of different threads about horizontal text animation/text scrolling, but unfortunately none of them give smooth scrolling with repeatable text. I have tried double/thickness animation using various WPF controls containing text. Also tried animating with visual brush which gives me by far the most elegant scrolling compared to other approaches (for e.g. playing with Canvas.Left property etc.) but that too goes blur the text, if the text length or the animation speed is too high.
I'm over to a pure DirectX C# implementation using SharpDX library. Should also mention that I'm a beginner with DirectX programming. Here is the code:
public void RunMethod()
{
// Make window active and hide mouse cursor.
window.PointerCursor = null;
window.Activate();
var str = "This is an example of a moving TextLayout object with no snapped pixel boundaries.";
// Infinite loop to prevent the application from exiting.
while (true)
{
// Dispatch all pending events in the queue.
window.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent);
// Quit if the users presses Escape key.
if (window.GetAsyncKeyState(VirtualKey.Escape) == CoreVirtualKeyStates.Down)
{
return;
}
// Set the Direct2D drawing target.
d2dContext.Target = d2dTarget;
// Clear the target.
d2dContext.BeginDraw();
d2dContext.Clear(Color.CornflowerBlue);
//float layoutXOffset = 0;
float layoutXOffset = layoutX;
// Create the DirectWrite factory objet.
SharpDX.DirectWrite.Factory fontFactory = new SharpDX.DirectWrite.Factory();
// Create a TextFormat object that will use the Segoe UI font with a size of 24 DIPs.
textFormat = new TextFormat(fontFactory, "Verdana", 100.0f);
textLayout2 = new TextLayout(fontFactory, str, textFormat, 2000.0f, 100.0f);
// Draw moving text without pixel snapping, thus giving a smoother movement.
// d2dContext.FillRectangle(new RectangleF(layoutXOffset, 1000, 1000, 100), backgroundBrush);
d2dContext.DrawTextLayout(new Vector2(layoutXOffset, 0), textLayout2, textBrush, DrawTextOptions.NoSnap);
d2dContext.EndDraw();
//var character = str.Substring(0, 1);
//str = str.Remove(0, 1);
//str += character;
layoutX -= 3.0f;
if (layoutX <= -1000)
{
layoutX = 0;
}
// Present the current buffer to the screen.
swapChain.Present(1, PresentFlags.None);
}
}
Basically it creates an endless loop and subtracts the horizontal offset. Here are the challenges: I need repeatable text similar to HTML marquee without any gaps, Would probably need to extend it to multiple monitors.
Please suggest.
I don't know neither how to use DirectX nor sharpdx, but if you want you can consider this solution
I had a similar problem a while ago, but with the text inside a combobox. After a bounty i got what i was looking for. I'm posting the relevant piece of code as an example, but you can check the complete answer here
Basically, whenever you have a textblock/textbox that contain a string that cannot be displayed completely, cause the length exceed the textblock/box lenght you can use this kind of approach. You can define a custom usercontrol derived from the base you need (e.g. SlidingComboBox : Combobox) and define an animation for you storyboard like the following
_animation = new DoubleAnimation()
{
From = 0,
RepeatBehavior = SlideForever ? RepeatBehavior.Forever : new RepeatBehavior(1), //repeat only if slide-forever is true
AutoReverse = SlideForever
};
In my example i wanted this behaviour to be active only when the mouse was on the combobox, so in my custom OnMouse enter i had this piece of code
if (_parent.ActualWidth < textBlock.ActualWidth)
{
_animation.Duration = TimeSpan.FromMilliseconds(((int)textBlock.Text?.Length * 100));
_animation.To = _parent.ActualWidth - textBlock.ActualWidth;
_storyBoard.Begin(textBlock);
}
Where _parent represent the container of the selected item. After a check on the text lenght vs combobox lenght i start the animation and end it at the end of the text to be displayed
Note that in the question i mentioned there are also other soltions. I'm posting the one that worked for me

Telerik RadEditor move cursor while dragging

I have a C# webforms page where I want to drag html elements into a telerik radeditor. This part is working as expected except that when you drag an element onto the editor I want the cursor position in the radeditor to follow the mouse. It is set up similar to this demo on Teleriks web site. Except I am using a listview instead of treeview.
http://demos.telerik.com/aspnet-ajax/editor/examples/treeviewandeditor/defaultcs.aspx
I have tried simulating clicks on the radeditor to move the cursor, but no luck there. Any ideas?
Edit:
I have made a semi-working solution last week. Its far from perfect but I decided to share it in case some one else wants to make it better.
function controlDragging(sender, args) {
var event = args.get_domEvent();
var editor = $find("radEditLayout");
if (isMouseOverEditor(editor, event)) {
var x = event.pageX - event.offsetX;
var y = event.pageY - event.offsetY;
var node = editor.get_document().elementFromPoint(x, y);
if (node) {
setCaret(editor, node, 0);
}
}
}
function setCaret(editor, element, position) {
var selection = editor.getSelection(),
range = selection.getRange(true);
if (range.setStartAfter) {//W3 range
range.setStartAfter(element);
}
else { //IE7/8 textRange
range.moveToElementText(element);
range.moveStart('character', position);
}
range.collapse(true);
selection.selectRange(range);
}
function isMouseOverEditor(editor, event) {
return $telerik.isMouseOverElementEx(editor.get_contentAreaElement(), event);
}
Any more suggestions??
Perhaps you will be able to figure out something with ranges, but I am not sure exactly how as I have not used them. Here are the basics on getting an already selected range http://www.telerik.com/help/aspnet-ajax/editor-getselection-1.html and here is how to get the document object so you can use ranges in it: http://www.telerik.com/help/aspnet-ajax/editor-getting-reference-to-radeditor-documentobject.html. Perhaps this can help you get started but I think it will be a lot of work: How to set caret(cursor) position in contenteditable element (div)? because I am not sure how you can calculate the position at which you want the cursor from the mouse coordinates.
I know this post is old but perhaps others can benefit from it. Here's a snippet that helped me drop at a random position in the RadEditor content area. It does not involve moving the cursor position.
kendoDropTarget({
drop: function(e) {
debugger;
var top = e.draggable.drag.y.location - $('.k-content').offset().top;
var left= e.draggable.drag.x.location - $('.k-content').offset().left;
element.css({
top: top + 'px',
left: left + 'px'
});
$('.overlay').remove();
$('.k-content').contents().find('body').html($('.k-content').contents().find('body').html() + $(element).outerHTML());
}

ScrollBar and Caret Position screwed up after assigning lines in RichTextBox

My issue is that when I write over the Lines attribute of a RichTextBox the cursor flies to the top of the text box, and sticks there. I cannot move it at all, no arrow keys or mouse work. Here is my code,
Code: (This is called when the caret changes position without typing) arrow keys or mouse click
private void UpdateVisibleLines()
{
string[] tmpArr = this.Lines;
if (this.LineCount > 5)
{
tmpArr[3] = "blah";
}
this.Lines = tmpArr;
}
I was reading and figured out myself also that I cannot do this to assign new strings for each line in a text box
rtb.Lines[i] = "Blah";
I have to make a tmp array and then assign rtb.Lines to that. I figure my problem is when I assign the rtb's text to be the new array. But I cannot figure out why the caret goes the the top of the text, and then stays there...

Categories