UITextField with a placeholder containing an image and text - swift

is there any way I could have a magnifier icon stuck to my placeholder in a UITextField like the below:
I tried to override leftViewRectForBounds(bounds: CGRect):
override func leftViewRectForBounds(bounds: CGRect) -> CGRect {
var superRect = super.leftViewRectForBounds(bounds)
superRect.origin.x += 80
return superRect
}
but it didn't work

You can add images to text using NSAttributedString and NSTextAttachment.
I haven't used them in a while but I believe you can do something like this...
let magnifyingGlassAttachment = NSTextAttachment(data: nil, ofType: nil)
magnifyingGlassAttachment.image = UIImage(named: "MagnifyingGlass")
let magnifyingGlassString = NSAttributedString(attachment: magnifyingGlassAttachment)
now you can use the magnifyingGlassString attributed string and add it as part of the attributed text to the UITextField.
I believe you can also specify exactly how the magnifying glass renders alongside the string (how it wraps etc...)
Something like this...
var attributedText = NSMutableAttributedString(attributedString: magnifyingGlassString)
let searchString = NSAttributedString(string: "Search for stuff")
attributedText.appendAttributedString(searchString)
textField.attributedPlaceholder = attributedText

You can add a image view or a custom view that displays this icon over the text field by properly placing it over and set up appropriate layout constraints. You will be adding this view as a sibling and not subview though.

Related

Swift: programmatically locate a UITextFelds UILabel and containing UIView container

I have a form with a UIView wrapping around a UILabel and UITextField. When a user enters the field I would like to change the colour of the label and the border colour of the view container.
If I call a function on the firstResponder I will need to find the text field's corresponding label and view copntainer.
I thought to have a firstResonder function for each field and in each function send the corresponding outlets (textfield, label, view) to a function which handles the colour changes for the label and view border.
This is not terrible but I and sure this can be accomplished more efficiently.
Any pointers please.
edit:
I changed my requirement slightly to place the label inside the textfield and highlight the textfield border instead of the encapsulating view.
This is what I ended up with:
override func viewDidLoad() {
super.viewDidLoad()
firstNameLabel.connect(with: firstName)
}
extension UILabel {
#objc
func editingChanged(textField: UITextField) {
}
#objc
func editingDidBegin(textField: UITextField) {
self.textColor = UIColor.blue
textField.layer.borderColor = UIColor.blue.cgColor
}
#objc
func editingDidEnd(textField: UITextField) {
self.textColor = UIColor.green
textField.layer.borderColor = UIColor.green.cgColor
}
func connect(with textField:UITextField){
//textField.addTarget(self, action: #selector(UILabel.editingChanged(textField:)), for: .editingChanged)
textField.addTarget(self, action: #selector(UILabel.editingDidBegin(textField:)), for: .editingDidBegin)
textField.addTarget(self, action: #selector(UILabel.editingDidEnd(textField:)), for: .editingDidEnd)
textField.layer.borderColor = UIColor.gray.cgColor
textField.layer.borderWidth = 1;
textField.layer.cornerRadius=10
}
}
The usual thing is to give each member of each group a corresponding tag. Since viewWithTag drills down to find any view with the given tag, the problem is solved if you know how to convert the tag value of the view you have to the tag value of the view you want.
For example, text field 10, view 110, label 210; text field 11, view 111, label 211; and so on. Or whatever system suits your fancy.
Alternatively just walk the view hierarchy. The view is the text field's superview, and the label is the first subview of the view that is a label.

How can I animate the change of the navigation bar title

I am looking for a way to run a custom CAAnimation on the UINavigationBar title.
More precisely, I am looking for a way to access the label which displays navigationItem.title and run animations on that.
It is certainly possible to manually create a UILabel and set the navigationBar.titleView accordingly.
This however seems to be too much effort for a hopefully simple problem. Plus, it will not work well with large titles on the UInavigationBar.
The title text is accessible as topItem.text. There is no way to directly access the label which is displaying this text.
So if you want to animate this label, you first have to search for it in the subview of the NavigationBar.
Then, you can apply animations on this label.
See below for an example that fades in the new title from the right.
/// Fades in the new title from the right
///
/// - Parameter newTitle: New title to display on the navigation item
func animateTitle(newTitle: String) {
// Title animation code
let titleAnimation = CATransition()
titleAnimation.duration = 0.25
titleAnimation.type = CATransitionType.push
titleAnimation.subtype = CATransitionSubtype.fromRight
titleAnimation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.easeInEaseOut)
// Find the Label which contains the topitem title
if let subviews = navigationController?.navigationBar.subviews {
for navigationItem in subviews {
for itemSubView in navigationItem.subviews {
if let largeLabel = itemSubView as? UILabel {
largeLabel.layer.add(titleAnimation, forKey: "changeTitle")
}
}
}
}
navigationItem.title = newTitle
}

copying label text to clipboard when clicked [duplicate]

This question already has answers here:
How to make a UILabel clickable?
(12 answers)
Closed 3 years ago.
first I have to make UILabel clickable and when it clicked it should copy its text to clipboard. I am using Xcode 10 with swift 5.1.
so firstly I am expecting label to be clickable and after that, this click action copy its text to clipboard. this is a basic level program.
To make the label "clickable" :
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(labelDidGetTapped:))
yourLabel.userInteractionEnabled = true
yourLabel.addGestureRecognizer(tapGesture)
Then, to retrieve the text from the label and copy it to the clipboard :
#objc
func labelDidGetTapped(sender: UITapGestureRecognizer) {
guard let label = sender.view as? UILabel else {
return
}
UIPasteboard.general.string = label.text
}
Note that there won't be any effect when tapping the text, it would be best to present some kind of feedback to the user, by animating the label's alpha for example
Part one of the answer can be followed as -
#IBOutlet weak var clickAble: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// this code is for making label clickable.
clickAble.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapFunction))
tap.numberOfTapsRequired = 1
clickAble.addGestureRecognizer(tap)
}
Part 2nd of answer is as-
#objc func tapFunction(sender:UITapGestureRecognizer)
{
// this is for copying label text to clipboard.
let labeltext = clickAble.text
UIPasteboard.general.string = labeltext
}
}
Try making user interaction enabled. For example:
yourLabel.isUserInteractionEnabled = true
Check this previous thread. This question has already been answered.
How to make a UILabel clickable?
For copying text to your clipBoard.
UIPasteboard.general.string = yourLabel.text

UITextView Height Adjustment

I'm trying to create a ViewController which will hold some large text. I used UILabel but since the text can be long, it won't work. Trying to switch to UITextViewbut I'm having some problems.
I'm using ScrollView since there is a image on the top and button on the bottom. So I don't it scrolling inside the UITextView itself. I've disabled it.
I want to Text to height itself automatically according to the text length. So it can scroll with the images, buttons etc. Just like the apps Instapaper, Medium, Pocket etc.
I've tried all the code and solutions on StackOverflow, but they either didn't work or they were Objective-C.
Storyboard Structure:
View Controller -> View -> ScrollView -> Image, TextView, Button
class ViewController: UIViewController {
#IBOutlet weak var textView: UITextView!
var theContent = fromClass.text
override func viewDidLoad() {
super.viewDidLoad()
textView.text = theContent
}
}
There is few ways to change the size of the UITextView
extension String {
func bounds(approximated width: CGFloat, approximated height: CGFloat, font: UIFont) -> CGRect {
let size = CGSize(width: width, height: height)
let attribs = [NSAttributedStringKey.font: font]
return NSString(string: self).boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attribs, context: nil)
}
}
approximated width = width of your UITextView I assume it is going to be static value which you won't change.
approximated height = minimal height of your UITextView.
The method going to return frame of your text input. Take from it height property and depending of how big is that change the size of the UITextView.
If it won't satisfy you, you can use another way.
func heightOfString(_ attributes: [NSAttributedKeyString : Any]) -> CGFloat {
let size = self.size(withAttributes: attributes)
return size.height
}
The same usage as from above.
Adjust your view hierarchy to the following view hierarchy :
View Controller -> View -> ScrollView -> View1 -> Image, UILabel, Button
1- give view1 top-left-bottom-right constraints and and align it center X to it's parent view
2- add UIImageView in the top of View1 and give it top-left-right constraint and a fixed height constraint.
3- add a UILabel and give it top constraint to the image and right-bottom-left constraint to it's superview.
make UILabel number of lines = 0
The content not should be scrollable.
Note that: in your case; you do not need UITextView .
If you want to use UITextView:
1- add a height constraint to the UITextView and connect an outlet to it
called: constTextViewHeight
let textViewContentHeight = textView.contentSize.height//call this line after adding the text to the textView
self.constTextViewHeight.contant = textViewContentHeight
self.view.layoutIfNeeded()

How to add an image/button to a UITextView? With auto line break?

I want to add an image/button to my UITextView and the text should automatically make a line break that the image/button fits.
Second question. I want to make a button called "move image/button" and then the user can move the image/button through the UITextView and the text should adjust.
PS: like in "Pages" for mac or "Word" for Windows
This is decidedly non-trivial. For starters, you can't simply embed a UIImage inside a UITextView and even if you could text wouldn't magically flow around it. What you'll need to do is create your own object based on a UITextView that substantially extends its capabilities to provide such editing tools.
For a heads-up as to what you're getting into you might want to take a look at the example Text Editor source code from the Omni Group.
Use the attributedText property of UITextView with an NSAttributedString with NSTextAttachment with image. Note that the UITextView must be Selectable (in Storyboard).
Swift demonstration:
let attributedImage = NSAttributedString(with: #imageLiteral(resourceName: "myImage"))
let attributedText = NSMutableAttributedString(string: "Hello ")
attributedText.append(attributedImage)
textView.attributedText = attributedText
Where the attributedImage is built from those convenience initializers:
extension NSAttributedString {
convenience init(with image: UIImage) {
self.init(attachment: NSTextAttachment(with: image))
}
}
extension NSTextAttachment {
convenience init(with image: UIImage) {
self.init()
self.image = image
// adjust origin if needed
self.bounds = CGRect(origin: .zero, size: image.size)
}
}
This solution works for: iOS 7.0, macOS 10.11, tvOS 9.0, *.