ios: how to start cursor at specific position? - ios

I want cursor at specific position.
I show my requirement in image.
let arbitraryValue: Int = 5
if let newPosition = txtroutine.position(from: txtroutine.beginningOfDocument, offset: arbitraryValue) {
txtroutine.selectedTextRange = txtroutine.textRange(from: newPosition, to: newPosition)
}

I have something like this but my code is in obj-c hope you can make it in swift,
Get the current position of cursor
- (NSInteger)cursorPosition
{
UITextRange *selectedRange = self.selectedTextRange;
UITextPosition *textPosition = selectedRange.start;
return [self offsetFromPosition:self.beginningOfDocument toPosition:textPosition];
}
// set cursor at your specfic location
- (void)setCursorPosition:(NSInteger)position
{
UITextPosition *textPosition = [self positionFromPosition:self.beginningOfDocument offset:position];
[self setSelectedTextRange:[self textRangeFromPosition:textPosition toPosition:textPosition]];
}

You can achieve this by overriding -textRectForBounds:. It will only change the inset of text i.e in your case it's cursor.
You need to subclass UITextField for that.
class PaddedTextfield: UITextField {
var horizontalInsetValue: CGFloat = 0
var verticalInsetValue: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: horizontalInsetValue, dy: verticalInsetValue)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: horizontalInsetValue , dy: verticalInsetValue)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: horizontalInsetValue, dy: verticalInsetValue)
}
}
You can use this textfield wherever you want.

you can use leftView property of UITextField to set position as per your requirement :
//add a 12pt padding to the textField
Swift 3.0 :
textField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 0))
textField.leftViewMode = .always
Try this , feel free to comment .

my problem is solved by adding this simple line in viewdidload()
self.txtroutine.layer.sublayerTransform = CATransform3DMakeTranslation(15, 0, 0);

Related

Tether uilabel closely to the text being input to UITextField

I want the currency abbreviation uilabel closely follow text being input into UITextField. What's a good way to
calculate where did the text being input ended so
that
func rightViewRect(forBounds bounds: CGRect) -> CGRect
can calculate the label rect properly?
Among other things I've ended up with this helper:
func rightViewRect(bounds: CGRect,
label: UILabel,
field: UITextField
) -> CGRect
{
let measure = UILabel()
measure.font = field.font
if field.text?.isEmpty ?? true {
measure.text = field.placeholder
} else {
measure.text = field.text
}
let cs = measure.intrinsicContentSize
let lcs = label.intrinsicContentSize
guard lcs.width > 0 else {
return .zero
}
let magicSpace = CGFloat(2)
let unclipped = CGRect(x: cs.width + magicSpace, y: 0, width: lcs.width, height: bounds.height)
let clipped = unclipped.intersection(bounds)
return clipped
}

How to display clear button in left side of UITextField?

I'm developing an app in Arabic language and I have UITextField with textAlignment right. Now I want to show the clear button of the textField in left side. Is it possible to do this without adding a custom button?
Current position
Desired position
Use below category and make sure your text alignment should be right :)
#interface UICrossButtonTextField:UITextField
- (CGRect)clearButtonRectForBounds:(CGRect)bounds;
#end
#implementation UICrossButtonTextField
- (CGRect)clearButtonRectForBounds:(CGRect)bounds {
CGRect originalRect = [super clearButtonRectForBounds:bounds];
return CGRectOffset(originalRect, -originalRect.origin.x+5, 0); }
- (CGRect)editingRectForBounds:(CGRect)bounds {
CGRect originalRect = [super clearButtonRectForBounds:bounds];
bounds = CGRectMake(originalRect.size.width, bounds.origin.y, bounds.size.width-originalRect.size.width, bounds.size.height);
return CGRectInset(bounds, 13, 3);
}
#end
Although I would recommend to check this answer for handling Left-to-Right App languages, as a workaround you could follow userar's answer, the following code snippet is a Swift 3 version of his answer:
Create a custom UITextField class, as follows:
class CustomTextField: UITextField {
private var originalRect = CGRect.zero
override func awakeFromNib() {
super.awakeFromNib()
originalRect = super.clearButtonRect(forBounds: bounds)
clearButtonMode = .whileEditing
textAlignment = .right
}
override func clearButtonRect(forBounds bounds: CGRect) -> CGRect {
return originalRect.offsetBy(dx: -originalRect.origin.x + 5, dy: 0)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
let bounds = CGRect(x: originalRect.size.width, y: bounds.origin.y, width: bounds.size.width-originalRect.size.width, height: bounds.size.height)
return bounds.insetBy(dx: 13, dy: 3)
}
}
The output would be:
SWIFT 3 syntax:
class TextFields: UITextField {
// You will need this
private var firstPlace = CGRect.zero
override func awakeFromNib() {
super.awakeFromNib()
firstPlace = super.clearButtonRect(forBounds: bounds) // to access clear button properties
/* uncomment these following lines if you want but you can change them in main.storyboard too
clearButtonMode = .whileEditing // to show the clear button only when typing starts
textAlignment = .right // to put the text to right side
*/
}
// Function to change the clear button
override func clearButtonRect(forBounds bounds: CGRect) -> CGRect {
return firstPlace.offsetBy(dx: -firstPlace.origin.x + 5, dy: 0)
}
}
hope it works

Change the text layout in a UITextField

Below is an image of some UITextFields. Regarding the large one on the bottom, how do I get it to start text at the top left (not the middle), and how do I get them all to start a bit to the right. As you can see, they are awkwardly close to the left edge.
For textField, override following methods:
class InsetTextField: UITextField {
var inset: CGFloat = 10
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: inset, dy: 0)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: inset, dy: 0)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: inset, dy: 0)
}
}
For textView:
textView.contentInset = UIEdgeInsetsMake(inset, inset, inset, inset);
And you can be involved when the textView is done editing, check out this question.
You can sublcass to a custom TextField:
import UIKit
class CustomTextField: UITextField {
var inset:CGFloat = 12 // You can set the inset you want
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: inset, dy: 0)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: inset, dy: 0)
}
}
The result, you can see the inset of the CustomTextField:
Edit
By default, UITextFields only have one line. Based off your image, I'd assume you want the user to have space to type a paragraph. For paragraphs, it is better to use UITextViews. It'd be a simpler solution for your problem.
I always use TextViews for biographies because it just makes my life much easier.
add left padding of your textfield
let paddingVie = UIView(frame: CGRect(x: 0, y:0, width: 10, height: 10))
yourtextField.leftView = paddingVie
yourtextField.leftViewMode = .always
for textview add
yourTextVieName.textContainerInset =
UIEdgeInsetsMake(8,5,8,5); // top, left, bottom, right

UITextField's placeholder margin and initial cursor margin [duplicate]

This question already has answers here:
Add lefthand margin to UITextField
(9 answers)
Closed 6 years ago.
I have a textfield with some placeholder. I want to give the margin of 20PX from left to show the placeholder and also wants to set initial cutsor at same margin.
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textField.leftView = paddingView;
textField.leftViewMode = UITextFieldViewModeAlways;
You have to create a subclass of UITextField and override the textRectForBounds: and editingRectForBounds: methods to return an insetted rect.
You could do something similar to:
func textRectForBounds(bounds: CGRect) -> CGRect {
return adjustBounds(bounds)
}
func editingRectForBounds(bounds: CGRect) -> CGRect {
return adjustBounds(bounds)
}
private func adjustBounds(bounds: CGRect) -> CGRect {
var newBounds = bounds
newBounds.origin.x += 20
newBounds.size.width -= 20
return newBounds
}
// If you need to place the UITextField placeholder in the initial 20px,
// you have to override this method as well to provide the right rect.
func placeholderRect(forBounds bounds: CGRect) -> CGRect {
var newBounds = bounds
newBounds.origin.x = 0
newBounds.size.width = 20
return newBounds
}
Reference: Text inset for UITextField?
You can create a custom UITextField.
Implement following methods and set Inset value as required
// placeholder position
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectInset(bounds, 10, 10);
}
// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
return CGRectInset(bounds, 10, 0);
}
For placeholder position:
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectInset( self.bounds , margin position , margin position );
}
For text position:
- (CGRect)editingRectForBounds:(CGRect)bounds {
return CGRectInset( self.bounds , margin position ,margin position );
}

How to customise UISlider height

I have project in which have to customise UISlider element.
I wondering if someone knows how to change, or is it possible to change height of UISlide bar line.
I tried something like this but don't work:
let customBounds = CGRect(origin: bounds.origin,
size: CGSize(width: bounds.size.width, height: 15.0))
feedbackSlider.trackRectForBounds(customBounds)
Thanks
i hope that you want edit it in storyboard, and only the line size, use it in your custom UISlider
class CustomSlide: UISlider {
#IBInspectable var trackHeight: CGFloat = 2
override func trackRectForBounds(bounds: CGRect) -> CGRect {
//set your bounds here
return CGRect(origin: bounds.origin, size: CGSizeMake(bounds.width, trackHeight))
}
}
Overriding trackRect is a way to go, however if you're using additional UISlider's views like minimumValueImage, maximumValueImage you would also need to take their bound into account, otherwise they will overlap with slider’s track. As a shortcut you can simply use super's func:
Fixed version.
Swift 3+
#IBDesignable
class CustomSlider: UISlider {
/// custom slider track height
#IBInspectable var trackHeight: CGFloat = 3
override func trackRect(forBounds bounds: CGRect) -> CGRect {
// Use properly calculated rect
var newRect = super.trackRect(forBounds: bounds)
newRect.size.height = trackHeight
return newRect
}
}
You can override a method in you custom slider
For Objective-C
- (CGRect)trackRectForBounds:(CGRect)bounds {
CGRect rect = CGRectMake(0, 0, 100, 30);//change it to any size you want
return rect;
}
For Swift
override func trackRectForBounds(bounds: CGRect) -> CGRect {
var rect:CGRect = CGRectMake(0, 0, 100, 30)
return rect
}
Swift 3
class MySlide: UISlider {
#IBInspectable var height: CGFloat = 2
override func trackRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(origin: bounds.origin, size: CGSize(width: bounds.width, height: height))
}
}
Swift 4 version without thumbImage.
class CustomSlider: UISlider {
#IBInspectable var trackHeight: CGFloat = 2
override func trackRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(origin: bounds.origin, size: CGSize(width: bounds.width, height: trackHeight))
}
}
I think the answers above have a flaw: the origin of the track rect must be offset to account for the change in height of the track, otherwise it will show up off-center. Here is the way I did it:
class CustomSlider: UISlider {
#IBInspectable var sliderTrackHeight : CGFloat = 2
override func trackRect(forBounds bounds: CGRect) -> CGRect {
let originalRect = super.trackRect(forBounds: bounds)
return CGRect(origin: CGPoint(x: originalRect.origin.x, y: originalRect.origin.y + (sliderTrackHeight / 2)), size: CGSize(width: bounds.width, height: sliderTrackHeight))
}
}
U can easily get it done by subclassing UISlider. see following code
class CustomUISlider : UISlider
{
override func trackRectForBounds(bounds: CGRect) -> CGRect {
//set your bounds here
return bounds
}
}
You should be able to subclass the UISlider and then implement:
- (CGRect)trackRectForBounds:(CGRect)bounds
Just return the new CGRect here.
If you're using autolayout you can set a height constraint on the UISlider in the storyboard. if you need to change it at runtime - create an IBOutlet for the constraint and modify its .constant value.

Resources