7

I need to add few labels on top of an UIImageView. The labels' text can be changed by tapping on them. What is the best way to achieve this? I am using Swift programming language. Looking up some solutions on stackoverflow, I found a couple of walkthroughs that use String.drawInRect method to draw some text in a rectangle which is then placed on the UIImageView. But like this I don't think I will be able to change the text, or even recognize a touch event on them. Please help.

UPDATE

My code so far:

override func viewDidLoad() {
    super.viewDidLoad()
    let img = UIImage(named: "Image")
    let imgView = UIImageView(image: img)

    self.view.addSubview(imgView)

    var myLabel = UILabel()
    myLabel.text = "Hello There"
    myLabel.textColor = UIColor.redColor()
    myLabel.font = UIFont(name: "Marker Felt", size: 20)
    myLabel.accessibilityIdentifier = "this is good!"
    myLabel.frame = CGRect(x: img!.size.width/2 /* - myLable.width / 2 ? */, y: 0, width: img!.size.width, height: 40)
    imgView.addSubview(myLabel)
    imgView.userInteractionEnabled = true
    myLabel.userInteractionEnabled = true
    let tapGesture = UITapGestureRecognizer(target: self, action: "handlePanGesture:")
    myLabel.addGestureRecognizer(tapGesture)
}

func handlePanGesture(sender: UITapGestureRecognizer) {
    var senderView = sender.view as! UILabel
    print(senderView.text)
    senderView.text = "look how i changed!"
    print(senderView.accessibilityIdentifier)
}

So far the results are positive I have an image with the label on top of it that can respond to touch events. Now I need to find the label's width so that I can effectively place it in the center when required. Then I need to find a way to place the labels at exact coordinates relative to the image's top left corner as origin.

Any help in these two tasks will be hugely appreciated.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
PPrasai
  • 1,186
  • 13
  • 36

7 Answers7

7

Adding label on ImageView is best approach. but you can also do it by adding button on ImageView.

I created a example where i created a ImageView on storyboard and create its outlet in ViewController class and in viewDidLoad i created a label and add it to label and add UITapGestureRecognizer to label. when user taps label we changed the label text and it's position.

class ViewController: UIViewController {

 @IBOutlet weak var winterImageView: UIImageView!

 override func viewDidLoad() {
  super.viewDidLoad()

  let label = UILabel(frame: CGRect(x: 10, y: 0, width: self.winterImageView.frame.width - 10, height: 30))
  label.textColor = UIColor.redColor()

  label.userInteractionEnabled = true
  let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
  label.addGestureRecognizer(tapGesture)
  label.text = "Is Winter is coming, My Friend?"
  self.winterImageView.addSubview(label)

}

enter image description here

Change label text and position in handleTap

 /// handle tap here 
 func handleTap(sender: UITapGestureRecognizer) {

  let senderView = sender.view as! UILabel
senderView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: senderView, attribute: .CenterX, relatedBy: .Equal, toItem: self.winterImageView, attribute: .CenterX, multiplier: 1, constant: 0).active = true

NSLayoutConstraint(item: senderView, attribute: .CenterY, relatedBy: .Equal, toItem: self.winterImageView, attribute: .CenterY, multiplier: 1, constant: 0).active = true
 print(senderView.text)
senderView.text = "Yes!!! Winter is coming, My Friend!!"

}

enter image description here

You can download project from here InteractiveLabel

Sahil
  • 9,096
  • 3
  • 25
  • 29
  • @MicroR you can try by taking screenshot of the image http://stackoverflow.com/questions/25444609/screenshot-in-swift-ios – Sahil Apr 04 '17 at 09:22
2

I can see from the other answers and comments related to one another virtually same stuff.If you familiar using Cocoa pods then you will agree with my opinion.Always,Just look around yourself and pick the best.If you want your project goes smooth and steady then JLStickerTextView is your friend and its way to go.It's free,elegant and more vibrant label customisation project available to everyone and the best thing about this project is written in handy Swift.

Github Link: https://github.com/luiyezheng/JLStickerTextView

Features

  • You can add multiple Text to StickerTextView at the same time
  • Multiple line Text support
  • Rotate, resize the text with one finger
  • Set the Color, alpha, font, alignment, TextShadow, lineSpacing...... of the text
  • StickerTextView also handle the process of rendering text on Image Written in Swift

Note: In, My personal opinion.Way, the code been written in this projects simply superb and properly categorised.

Avaliable Text Attributes Reference:

enter image description here

MainView Screenshot from the project:

enter image description here

Output from my personal project based on JLStickerTextView.I, hope you will consider it.If you need any more information let me know...

enter image description here

Joe
  • 8,868
  • 8
  • 37
  • 59
  • in this i got it error can you solve it https://github.com/luiyezheng/JLStickerTextView/issues/10 – ItsMeMihir Dec 07 '16 at 06:04
  • stickerImageView.swift file – ItsMeMihir Dec 07 '16 at 06:15
  • 1
    Just comment out `stickerView.limitImageViewToSuperView()` from your mainVC and set your `stickerImageView` content mode to `aspectToFit` or `aspectToFill` as the forum recommended or code yourself(pretty easy to do) – Joe Dec 07 '16 at 06:25
  • can u provide example in swift 3 – ItsMeMihir Dec 07 '16 at 07:19
  • what do you mean?. stickerView will work after you convert to `Current Swift Syntex` . I believe you getting 85+ syntax error after you converted to Swift 3. you have to manually fix all of them.I know its a pain in the bm... – Joe Dec 07 '16 at 07:26
  • dont comment empty handed?. tell me whats error r you getting. may be i can help. if you show me something ? – Joe Dec 07 '16 at 07:43
  • i can't rotate sticker(Label) nd close and rotate buttons are not shown – ItsMeMihir Dec 07 '16 at 07:45
  • have you set image to your button(close & rotate)....i thing button won't comes with the project or may be is not visible?. I want to make it clear.stickerView project is not a easy or straight forward project...you need to workout many things to achieve what you after.it could take about a week?.You could implement new idea to the project once you fully understand the project....so take it easy , be patients? and stretch your time... – Joe Dec 07 '16 at 07:53
  • stickerView.currentlyEditingLabel.tintColor = UIColor.red stickerView.currentlyEditingLabel.rotateView?.image = UIImage(named: "rotate_img")?.withRenderingMode(.alwaysTemplate) stickerView.currentlyEditingLabel.closeView!.image = UIImage(named: "cancel_img")?.withRenderingMode(.alwaysTemplate) nd – ItsMeMihir Dec 07 '16 at 07:56
  • where you setting above code? .code should go inside your button action method should work and i want you to comment clearly as my time is limited:( – Joe Dec 07 '16 at 08:00
  • you dont need to set anything for rotate...project comes with that func by default....how you trying in `sim or iPhone?` – Joe Dec 07 '16 at 08:07
  • is user Intraction enabled on stickerViewImage? – Joe Dec 07 '16 at 08:16
  • how can i use custom font in this? means external font apply in this – ItsMeMihir Dec 08 '16 at 10:02
  • follow this post to use custom font to your project. http://stackoverflow.com/questions/40168344/xcode-8-custom-font-doesnt-show-up-in-interface-builder/40170579#40170579 from my answer try `step1 and 2` make sure `upvote` before you proceed or further comment? – Joe Dec 08 '16 at 10:14
  • but @Joe in this they Error in "adjustsWidthToFillItsContens" method they UIFont is nil return so they crash – ItsMeMihir Dec 08 '16 at 10:19
  • they don't found custom font – ItsMeMihir Dec 08 '16 at 10:22
  • custom font won't give you a crash. font simply won't work if you not set them up properly?... comment clearly how/where you getting the error?. i can't spend time for nothing.please respect my time? – Joe Dec 08 '16 at 10:25
  • hey this normal label ok but i want to use in JLStickerTextView in custom fonts – ItsMeMihir Dec 08 '16 at 10:33
  • what you mean did you look at the link?......`JLStickertextView` nothing to do with `custom font` ....font set by the `Xcode`?......Import custom font to your project -> update plist with font array -> update font name in `fontNamesArray` thats simple? – Joe Dec 08 '16 at 10:36
  • @ItsMeMihir I was facing same issue have you solved your Issue ? and could you please help me with this? – Khushbu Desai Oct 14 '17 at 08:37
  • @KhushbuDesai still I can’t get solution for that – ItsMeMihir Oct 14 '17 at 08:40
  • @ItsMeMihir :p i was thinking to solving errors , thanks for saving my time. have you found any alternative for this feature? i need to implement it in my Photo Editing app. – Khushbu Desai Oct 14 '17 at 08:42
  • @KhushbuDesai I think i found the way to do it while ago. but, I am not using this project anymore...so, i recommend you to give a request to the author or see any updates available... – Joe Oct 14 '17 at 08:46
  • @ItsMeMihir https://github.com/khush004/StickerView/tree/master here is code of JLStickerTextView which is error free with compatibility of swift 3.0 – Khushbu Desai Oct 25 '17 at 12:04
  • 1
    @KhushbuDesai Good Job – ItsMeMihir Oct 26 '17 at 11:19
2

github.com/khush004/StickerView/tree/master

here is code of JLStickerTextView which is error free with compatibility of swift 3.0

Khushbu Desai
  • 1,003
  • 1
  • 10
  • 32
1

You can use a label and add a gesture recognizer from which you can set an action.

EDIT (responding to OP comment) :

Basically you put an UILabel on top of your card, set a gesture recognizer on it, and set a hidden UITextField at the same position as your label. This way when you tap on it, you specify in your gesture recognizer method that the UI must set label as hidden and textfield as visible. When you're done (end editing), just save your changes and update the UI.

Damien
  • 3,322
  • 3
  • 19
  • 29
  • But how do I overlay that label over an UIImage? For example, suppose the image is background image of a visiting card and the labels are the textual fields in it. How do I make it so the users see what appears to be a normal visiting card but they should be able to update fields by tapping on them? – PPrasai Oct 04 '16 at 06:09
1

If you just want to center align your UILabel and UIImageView, you can use AutoLayout constraint.

NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: imageView, attribute: .CenterX, multiplier: 1, constant: 0).active = true

NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: imageView, attribute: .CenterY, multiplier: 1, constant: 0).active = true
xi.lin
  • 3,326
  • 2
  • 31
  • 57
1
func handlePanGesture(sender: UITapGestureRecognizer) {
       let senderView = sender.view as! UILabel
       print(senderView.text)
        senderView.textColor = UIColor.redColor()
       senderView.text = "look how i changed!"
       print(senderView.accessibilityIdentifier)
    }

Ouput :

sender.view?.frame

▿ Optional ▿ Some : CGRect ▿ origin : CGPoint - x : 0.0 - y : 0.0 { ... } ▿ size : CGSize - width : 335.0 - height : 28.0

Himanshu Moradiya
  • 4,769
  • 4
  • 25
  • 49
1

I use CALayers, gesture recognizers, and the hitTest method of the layers. Sample code below:

class ImageView: UIImageView {

    let tapGesture = UITapGestureRecognizer()

    let redLayer = CATextLayer()
    var redHitCounter:Int = 0
    let greenLayer = CATextLayer()
    var greenHitCounter:Int = 0

    override init(frame: CGRect) {
        super.init(frame: frame)
        setUpClickableLayers()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setUpClickableLayers()
    }

    private func setUpClickableLayers() {

        self.isUserInteractionEnabled = true

        tapGesture.numberOfTapsRequired = 1
        tapGesture.addTarget(self, action: #selector(changeText))
        self.addGestureRecognizer(tapGesture)

        redLayer.frame = CGRect(x: 40, y: 40, width: 100, height: 40)
        redLayer.backgroundColor = UIColor.red.cgColor
        redLayer.string = String(redHitCounter)
        redLayer.alignmentMode = kCAAlignmentCenter
        self.layer.addSublayer(redLayer)

        greenLayer.frame = CGRect(x: 40, y: 140, width: 100, height: 40)
        greenLayer.backgroundColor = UIColor.green.cgColor
        greenLayer.string = String(redHitCounter)
        greenLayer.alignmentMode = kCAAlignmentCenter
        self.layer.addSublayer(greenLayer)
    }

    internal func changeText(_ recognizer:UITapGestureRecognizer) {
        let p = recognizer.location(in: self)
        if (redLayer.hitTest(p) != nil) {
            redHitCounter += 1
            redLayer.string = String(redHitCounter)
        } else if (greenLayer.hitTest(p) != nil) {
            greenHitCounter += 1
            greenLayer.string = String(greenHitCounter)
        }
    }
}

A few notes:

(1) Remember to set your UIImageView's isUserInteractionEnabled to true. It took me an hour to debug why my UIImageView was seeing gestures!

(2) The hitTest() method works for the CALayer and all subclasses. Just remember to make the layer large enough to work on fat fingers.

(3) You can also use the pan and pinch gestures to move, rotate, and resize the target layer.