Change the UITextView Text Direction
You question have really interested me. So in a matter of hour I've came up with solution. It is far from perfect, but you can use it and fix remaining bugs.
This is a simple view controller with text view. You can add text typing it or you can set the value using
-(void) setText:(NSString*) txt;
So here is the code:
ReverseTextVC.h
@interface ReverseTextVC : UIViewController <UITextViewDelegate> {
NSMutableArray* _lines;
UITextView* _tv;
}
/**
Returns reversed text.
The lines is also updated. This array contains all lines. You should pass this array again if you want to append the text.
*/
+(NSString*) reverseText:(NSString*) text withFont:(UIFont*) font carretPosition:(NSRange*) cpos Lines:(NSMutableArray*) lines Bounds:(CGRect) bounds;
-(void) setText:(NSString*) txt;
@end
ReverseTextVC.m
@implementation ReverseTextVC
-(id) init {
if( self = [super init] ) {
_tv = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)];
_tv.textAlignment = UITextAlignmentRight;
_tv.delegate = self;
[self.view addSubview: _tv];
[_tv release];
_lines = [[NSMutableArray alloc] initWithCapacity: 10];
[_lines addObject: [NSMutableString stringWithCapacity: 255]];
}
return self;
}
-(void) dealloc {
[_lines release];
[super dealloc];
}
-(void) loadView {
UIView* v = [[UIView alloc] initWithFrame: CGRectMake(0, 20, 320, 480)];
self.view = v;
[v release];
}
-(void) setText:(NSString*) txt {
NSString* result = nil;
NSRange rng;
NSArray* words = [txt componentsSeparatedByString: @" "];
//we should do it iteratively (cause it's the simplest way =) )
for(NSString* word in words) {
word = [NSString stringWithFormat: @"%@ ", word];
for(int i=0; i<[word length]; ++i) {
NSRange r; r.length = 1; r.location = i;
result = [ReverseTextVC reverseText: [word substringWithRange: r]
withFont: _tv.font
carretPosition: &rng
Lines: _lines
Bounds: _tv.bounds];
}
}
_tv.text = result;
}
#pragma mark -
#pragma mark UITextViewDelegate
-(BOOL) textView:(UITextView*) textView shouldChangeTextInRange:(NSRange) range replacementText:(NSString*) text {
NSRange rng;
textView.text = [ReverseTextVC reverseText: text
withFont: textView.font
carretPosition: &rng
Lines: _lines
Bounds: textView.bounds];
textView.selectedRange = rng;
return NO;
}
#pragma mark -
#pragma mark Static
+(NSString*) reverseText:(NSString*) text withFont:(UIFont*) font carretPosition:(NSRange*) cpos Lines:(NSMutableArray*) lines Bounds:(CGRect) bounds {
cpos->length = 0;
cpos->location = 0;
if( [text length] ) {
if( ![text isEqualToString: @"\n"] ) {
[(NSMutableString*)[lines lastObject] insertString: text
atIndex: 0];
} else {
[lines addObject: [NSMutableString stringWithCapacity: 255]];
}
} else {
//backspace
//TODO:
NSRange del_rng;
del_rng.length = 1;
del_rng.location = 0;
if( [(NSMutableString*)[lines lastObject] length] ) {
[(NSMutableString*)[lines lastObject] deleteCharactersInRange: del_rng];
}
if( ![(NSMutableString*)[lines lastObject] length] ) {
[lines removeLastObject];
}
}
CGSize sz = [(NSString*)[lines lastObject] sizeWithFont: font];
if( sz.width >= bounds.size.width-15 ) {
NSMutableArray* words = [NSMutableArray arrayWithArray: [(NSString*)[lines lastObject] componentsSeparatedByString: @" "]];
NSString* first_word = [words objectAtIndex: 0];
[words removeObjectAtIndex: 0];
[(NSMutableString*)[lines lastObject] setString: [words componentsJoinedByString: @" "]];
[lines addObject: [NSMutableString stringWithString: first_word]];
}
NSMutableString* txt = [NSMutableString stringWithCapacity: 100];
for(int i=0; i<[lines count]; ++i) {
NSString* line = [lines objectAtIndex: i];
if( i<([lines count]-1) ) {
[txt appendFormat: @"%@\n", line];
cpos->location += [line length]+1;
} else {
[txt appendFormat: @"%@", line];
}
}
return txt;
}
@end
Hope it helps you =)
Detect text direction based on content
I've had this problem myself. With a little bit of search, made this extension for UITextView which detects the first letter's language and makes it RTL if it's needed.
You need to call the function after setting text, so you may want to call it in UITextViewDelegate text change" method.
extension UITextView {
func detectRightToLeft() {
if let text = self.text where !text.isEmpty {
let tagschemes = NSArray(objects: NSLinguisticTagSchemeLanguage)
let tagger = NSLinguisticTagger(tagSchemes: tagschemes as! [String], options: 0)
tagger.string = text
let language = tagger.tagAtIndex(0, scheme: NSLinguisticTagSchemeLanguage, tokenRange: nil, sentenceRange: nil)
if language?.rangeOfString("he") != nil || language?.rangeOfString("ar") != nil || language?.rangeOfString("fa") != nil {
self.text = text.stringByReplacingOccurrencesOfString("\n", withString: "\n")
self.textAlignment = .Right
self.makeTextWritingDirectionRightToLeft(nil)
}else{
self.textAlignment = .Left
self.makeTextWritingDirectionLeftToRight(nil)
}
}
}
}
Surely this is messy and not perfect. But it worked for me. You can get the idea.
Swift 3:
extension UITextView {
func detectRightToLeft() {
if let text = self.text, !text.isEmpty {
let tagschemes = NSArray(objects: NSLinguisticTagSchemeLanguage)
let tagger = NSLinguisticTagger(tagSchemes: tagschemes as! [String], options: 0)
tagger.string = text
let language = tagger.tag(at: 0, scheme: NSLinguisticTagSchemeLanguage, tokenRange: nil, sentenceRange: nil)
if language?.range(of: "he") != nil || language?.range(of: "ar") != nil || language?.range(of: "fa") != nil {
self.text = text.replacingOccurrences(of: "\n", with: "\n")
self.textAlignment = .right
self.makeTextWritingDirectionRightToLeft(nil)
}else{
self.textAlignment = .left
self.makeTextWritingDirectionLeftToRight(nil)
}
}
}
}
Related Topics
Url Scheme "Open Settings" iOS
Getting Button Action:Uicollectionview Cell
Swift "Bridging-Header.H" File Not Allowing Me to Instantiate Objective-C Classes in .Swift Files
Creating Thumbnail for Video in iOS
Allowing Single Digit in Uitextfield in iOS
Are Cookies in Uiwebview Accepted
Apns Notifications Not Reaching Devices Enrolled in Apple Mdm
Swift 3: Expression Implicitly Coerced from 'Uiview' to Any
Change Size of Uibarbuttonitem (Image) in Swift 3
Nsstring Containsstring Crashes
Swift - Uiimagepickercontroller - How to Use It
iOS in App Purchase: Test a Real Purchase Without Submitting to Apple
Modifying Ekparticipants (Attendees) in Eventkit Like Sunrise
React Native iOS Build:Can't Find Node
How to Debug "Invalid Bundle" Error Which Happens Only After Submitting to App Store
Flutter iOS Build Failed an Error of Pod Files: Podfile Is Out of Date