UITextView increment character to the left - ios

I have a UITextView that has a fixed width and height. I pre-populate the entire textfield with blanks.
I would like to insert a character with the push of a button that will erase the last blank character, insert my string character and then place the cursor at the beginning of the newly inserted string. I am trying to achieve inserting special fonts right to left and bottom to top.
It is working with the first button push and on the second button push the new value is inserted in the correct position to the left, however, the cursor will not move to the left after the second button push, it remains to the right after the second string insert.
Here is my code...
-(IBAction)chartP:(id)sender {
NSRange currentRange = myChart.selectedRange;
if (currentRange.length == 0) {
currentRange.location--;
currentRange.length++;
}
myChart.text = [myChart.text stringByReplacingCharactersInRange:currentRange
withString:[NSString string]];
currentRange.length = 0;
myChart.selectedRange = currentRange;
myChart.text = [myChart.text stringByAppendingString:#"p"];
myChart.selectedRange = NSMakeRange(myChart.selectedRange.location -1, 0);
}
Can someone assist me with what I am missing here to continually increment to the left with my string inserts?

How about flipping the text area:
myChart.transform = CGAffineTransformMakeScale(-1,-1);

It sounds like you are trying to implement right-to-left text direction by faking it. Why not do the real thing?
Here's a question that covers the topic:
Change the UITextView Text Direction
If you need bottom-to-top entry, and you have the ability to use a custom font, perhaps you can apply a transformation to the UITextView and y-flip it. Look at the transform property of UIView. (Things like the text selection loupe may break, but it's worth a try.)

Related

Set UiTextField cursor on top Swift IOS

I have a TextField in my storyboard with a height of 100 .
When I'm clicking the TextField the cursor is placed in center :
I would like to set the cursor position in the top left corner.
I tried :
let startPosition: UITextPosition = textField.beginningOfDocument
But it seems that the position is already at the beginning and when the height is extended the cursor stay in center.
How can it be done ?
Seems like you want a multiline UITextField. In that case you might want to take a look at UITextView, which should allow for what you want (docs)

Scroll to a specific part of a UITextView in Swift

In the Swift app I'm creating, the user can type some text into a text view and then search for a specific string within it, just like in Pages (and numerous others).
I have the index of the character they are searching for as an Integer (i.e., they are on the third instance of "hello" in the massive text block they typed in, and I know that's the 779th letter of the text view) and I am trying to automatically scroll the text view to the string they're on, so that it pops out (like it would in Pages).
I am trying to jump to the applicable string with this command:
self.textview.scrollRangeToVisible(NSMakeRange(index, 0))
but it never jumps to the right place (sometimes too far down, sometimes way too far up), often depending on screen size, so I know that index doesn't belong right there.
How can I correctly allow the user to jump to a specific string in a text view, by making the text view scroll to a certain character?
You can get string, which is before index 779, and then calculate the height of this string and then scroll to this point.
let string = textView.text.substringWithRange(Range<String.Index>(start: textView.text.startIndex, end: textView.text.startIndex.advancedBy(779)))// your <779 string
let size = string.sizeWithAttributes([NSFontAttributeName:yourFont])
let point = CGPointMake(0, size.height)
scrollView.setContentOffset(point, animated:true)
The other answer doesn't seem to work anymore (Jan 2021). But there is a simpler way now:
// Range specific to the question, any other works
let rangeStart = textView.text.startIndex
let rangeEnd = textView.text.index(rangeStart, offsetBy: 779)
let range = rangeStart..<rangeEnd
// Convert to NSRange
let nsrange = NSRange(range, in: textView.text)
// ... and scroll
textView.scrollRangeToVisible(nsrange)

How can I check out-of-sight characters in UITextField?

I have a UITextField that shrinks and expands when user input text. If the textfield's width reach the screen width, I want it to be right-aligned so user can see the last input characters. In other circumstance, I want it to be left-aligned.
Because the textfield's maximum width is not exactly the same with screen, I need to find a way to check if it has characters out of visible area.
Is there anyway to achieve this?
You could try checking the width of the string that is in the field and comparing it to the width of the field itself. It would look something like this -
CGSize textSize = [self.field.text sizeWithAttributes:#{NSFontAttributeName:self.field.font}];
// If the text is larger than the field
if (textSize.width > self.field.bounds.size.width) {
// There is text that is not visible in the field.
}
This is fairly rough, but should get you close.

What to do if label is bigger than parent UIVIew?

I have two multiline UILabels. The parent UIView only has a certain size (height) but the labels can contain a long string. What I want is that the first label is always shown (e.g. abbreviated with ... if it gets too long). If there is room the second label should be shown. Again if it's too long it should get abbreviated with ...
This is the constraint I'm currently using: V:|-5-[title]-0-[description]-(>=0)-|
In some cases the second label gets cut off like this:
What should I do? Do I have to change the constraint? Can I hide the second label somehow? But how should I detect when the label is cut off?
In another case the second label wasn't shown at all. The second label should also not overflow the parent UIView. How should one handle such cases?
I believe rounding occurs somewhere in iOS because the label would fit (one line and then at the end with ...) if there would be 0.75pt more space. So it draws it but it is cut off because of the missing 0.75pt space.
Now I took the following approach: Calculate if the second label (reference text which should be about one line) would fit in the parent view? And if not hide it. I only have code in C# but you should get the idea:
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
NSString referenceTextToMeasure = new NSString ("Lorem ipsum dolor sit amet.");
// take the font of the description label which was cut off
CGRect referenceTextRect = referenceTextToMeasure.GetBoundingRect (
new CGSize(this.Frame.Width, nfloat.MaxValue),
NSStringDrawingOptions.UsesLineFragmentOrigin,
new UIStringAttributes () { Font = descriptionLabelFont },
new NSStringDrawingContext ()
);
// 5 is the spacing constraint I have on the top
if ((this.Frame.Height - TitleLabel.Frame.Height - 5) < referenceTextRect.Height )
DescriptionLabel.Hidden = true;
}
Seems to work quite well, though a full test has to be made. You could also use a fixed height instead of referenceTextRect.Height and you would save some calculations. Nevertheless, the way I used allows of adapting the fonts so everything is dynamically calculated.

Why are the ranges for my formatted text shifting in iOS 7?

My app includes a text formatting tool that offers buttons for things like bold, italic and color and shows the formatted text by generating an NSAttributedString and setting that to the attributedText property of a UITextView. After the user selects text and taps a button, I get the selectedRange property of the UITextView, then get the current attributedText property of the UITextView, add another attribute to the text based on the selected range, and then assign it back to the attributedText property of the UITextView again.
Starting with iOS 7, my text formatting started displaying at the wrong location in the text, usually shifted a couple characters forward. After some testing I noticed that this only happened after an empty line (e.g., a paragraph of text with two line breaks after it) and the formatting was offset by one character for each empty line proceeding it.
After more testing I found that when I set the attributedText property for the first time, any sequence of two line breaks is changed to a line break, then a "line separator" character (Unicode 8232) and then the second line break. The new characters are definitely added by the attributedText assignment, as I can see from outputting the integer value of each character immediately before and immediately after that action. However, the selectedRange property of the UITextView ignores the line separator characters, so any range that it returns is now incorrect.
I've already found a workaround, which I'll add as an answer in a moment. I'm mainly posting this in case anyone else is having problems with it. Also, I've reported this to Apple as bug 15349335.
I wrote this method to adjust ranges returned by the selectedRange property to account for these extra line separator characters:
- (NSRange)adjustRangeForEmptyLines:(NSRange)range inText:(NSAttributedString *)text byChars:(int)chars {
int emptyLinesBeforeRange = 0;
int emptyLinesWithinRange = 0;
for (int i=0; i<(range.location + range.length); i++) {
int thisCharacter = [text.string characterAtIndex:i];
//NSLog(#"thisCharacter: %i", thisCharacter);
if (thisCharacter == 8232) {
if (i < range.location) {
emptyLinesBeforeRange++;
} else {
emptyLinesWithinRange++;
}
}
}
//NSLog(#"found %i + %i empty lines", emptyLinesBeforeRange, emptyLinesWithinRange);
range.location += (emptyLinesBeforeRange * chars);
range.length += (emptyLinesWithinRange * chars);
return range;
}
I can set the byChars argument to 1 or -1 depending on which way I want to adjust. This has been working for me for a few weeks now, but if anyone has an alternate solution, I'd be curious to see it.

Resources