Multiple touch event in single image view - ios

I would like to implement multiple touch event for single image view. For example, I have an image of India map, where I should be able to capture the touch event of different states. Can someone provide me some idea to implement this in objective c?

Well, quite an interesting question. The solution can be achieved in many ways.
Solution 1 :
Get an image with the states in different distinct colors. Then you can get the color at the point of touch and compare it with the color of the state.
So if the color at a point is RGB base 256 is ( 240, 125, 131 ) then the state is Maharashtra.
Note in this picture above some states have the same color so this exact image would not work.
To get the color at a pixel you can refer to this link.
Solution 2: (Coded in Swift but would work perfectly with Objective C tested with Obj-C link to it)
Get all the images of individual states.
Make a view a subclass of StateView in IB
Set the image and name of State in IB
If the touch is within the state it prints the state name as far as now for demo purposes.
Link to the project.
References :
Mark Moeykens Youtube
Hope this helps.
Result :

Yes i did it in one of my application. You need to keep tract of paths for states, then on tap, find the path in which the point lies.
In my case i had to devide the image with set of rectangles then i just noted down the first & list point (CGPoint) and save the height width of rectangle. Then based on this data i compared whether the point lies in which region.
How to fine the state area ?
You need to manually tap on boundary of area & get the CGPoint from touch default methods as:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let point = touches.first?.location(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let point = touches.first?.location(in: self)
touches.forEach { (touch) in
print(touch.location(in: self))
}
}

Related

iPhone back camera cannot focus correctly

I've been making an iOS camera app and trying to solve this problem for two days (but cannot solve this).
What I'm working on now is change the focus and exposure automatically depending on the user's tapped location. Sometimes it works fine (maybe about 20% in total), but mostly it fails. Especially when I try to focus on a far object (like 5+metre) or when there are two objects and try to switch the focus of one object to another. The image below is an example.
The yellow square locates where the user tapped and even though I tapped the black cup in the first picture, the camera still focuses on the red cup.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touchPoint = touches.first! as UITouch
let focusPoint = touchPoint.location(in: lfView)
print("focusPoint \(focusPoint)")
showPointOfInterestViewAtPoint(point: focusPoint)
setFocus(focusMode: .autoFocus, exposureMode: .autoExpose, atPoint: focusPoint, shouldMonitorSujectAreaChange: true)
}
func setFocus(focusMode: AVCaptureDevice.FocusMode, exposureMode: AVCaptureDevice.ExposureMode, atPoint devicePoint: CGPoint, shouldMonitorSujectAreaChange: Bool) {
guard let captureDevice = captureDevice else { return }
do {
try captureDevice.lockForConfiguration()
} catch let error as NSError { return }
if captureDevice.isFocusPointOfInterestSupported, captureDevice.isFocusModeSupported(focusMode) {
captureDevice.focusPointOfInterest = devicePoint
captureDevice.focusMode = focusMode
print("devicePoint: \(devicePoint)")
}
// other codes in here...
captureDevice.isSubjectAreaChangeMonitoringEnabled = shouldMonitorSujectAreaChange
captureDevice.unlockForConfiguration()
}
I called the setFocus function in touchesBegan function and both focusPoint & devicePoint comments show the same coordinate, like (297.5, 88.0).
When I tapped the black cup in the picture, I can see the iPhone camera is zooming in and out a little bit, like same as when I use the default iPhone camera app and try to focus on an object. So I guess my camera app is trying to focus on the black cup but it fails.
Since this is not an error, I'm not sure which code to change. Is there any clue what is going on here and what causes this problem?
ADD THIS PART LATER
I also read this document and it says
This property’s CGPoint value uses a coordinate system where {0,0} is the top-left of the picture area and {1,1} is the bottom-right.
As I wrote before, the value of devicePoint gives me more than 1, like 297.5, 88.0. Does this cause the problem?
Thanks to #Artem I was able to solve the problem. All I needed to do was convert the absolute coordinate to the value used in focusPointOfInterest (min (0,0) to max (1,1)).
Thank you, Artem!!

Xcode 9 Swift 4 - Reposition views by dragging

Im quite new to iOS development. But have years of programming experience.
Anyway, Im having a hard time finding a solution for my problem.
In my app i render rows of colored circles based on data from the server.
Each of these circles has different properties set to them on the server.
One of these is the "offset" property.
This should be used to render the circle with a distance from its left sibling, or the start of the parent view if its the first.
Each circle should then also be able to be moved by dragging it to the right or left. But never less then 0 from its left sibling.
In android this was very easy, just set the left-margin on drag, and all was good.
But in xcode im having a very hard time figuring out how to get this done.
Im sure its me thats way to inexperienced. So I hope someone that has a bit more knowledge about swift can help me with this.
Heres some images to make clear what Im looking to achive.
First render where one circle has an offset
The gesture where the 3. last circle is drages to the right
The result of the gesture
I need this to move seamless, so not reposiotioning after the gesture ends, but move along with the finger.
As you can see, the circles right of the one that is drages, keep their relative position to the one that is moved.
Thank you.
There are couples of ways to do this.The First possible solution can be using the Swipe gestures to move the objects.
override func viewDidLoad() {
super.viewDidLoad()
let swipeGesture = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
swipeGesture.direction = [.Down, .Up]
self.view.addGestureRecognizer(swipeGesture)
}
func handleSwipe(sender: UISwipeGestureRecognizer) {
print(sender.direction)
}
Use these Gestures to move along the objects with your fingers either you can use .left and .right gestures depending upon your need.
The Second solution for drag components can be a Pan Gesture
func detectPan(recognizer:UIPanGestureRecognizer) {
var translation = recognizer.translationInView(self.superview!)
self.center = CGPointMake(lastLocation.x + translation.x, lastLocation.y + translation.y)
}
The translation variable detects the new coordinates of the view when panning. The center of the view will be adjusted according to the changed coordinates.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// Promote the touched view
self.superview?.bringSubviewToFront(self)
// Remember original location
lastLocation = self.center
}
When the view is clicked, the current view will be displayed in front of the other views and the center of the view will be assigned to the lastlocation variable
Hope this helps.

Create clickable body diagram with Swift (iOS)

I'm trying to recreate something for a iOS app (Swift) which I already made in HTML5 (using map area-coords).
I want to show a human body diagram that interacts with user clicks/touches. The body exists of let's say 20 different parts, and the user can select one or more body-parts. For every body-part there is a selected-state image that should appear when a part is selected. Clicking on a selected part will deselect it. After selecting one or more parts, the user can continue and will get some information about these parts in a next viewcontroller. I am attaching a simplified image to explain my goal.
Can somebody explain what the best way is to achieve this goal? Is there a comparable technique that can be used in Swift to create such an interactive image?
Thanks!
There is no built-in mechanism for detecting taps in irregular shapes. The standard UIView tap detection uses frame rectangles. (Likewise with CALayers, as suggested by sketchyTech in his comment above.)
I would suggest drawing your body regions as bezier paths. You could create a custom subclass of UIView (BodyView) that would manage an array of BodyRegion objects each of which include a bezier path.
The UIBezierPath class includes a method containsPoint that lets you tell if a point is inside the path. Your BodyView could us that to decide which path object was tapped.
Bezier paths would handle both drawing your body regions and figuring out which part was tapped.
A very simple way to achieve this, would be to place invisible buttons over the areas, then hook every one up to an IBAction and put anything you want to happen inside.
#IBAction func shinTapped(sender: UIButton) {
tappedCounter = 0
if tappedCounter == 0 {
// set property to keep track
shinSelected = true
// TODO: set button image to selected state
// increment counter
tappedCounter++
}else{
// set property to keep track
shinSelected = false
// TODO: set button image to nil
// reset counter
tappedCounter = 0
}
This might get a little tricky to layout, so that every button sits in the right spot, but if you work with size classes it is totally doable.
I am sure there is a more elegant way to do it, but this is one way.
Fixed!
First I added sublayers to the UIImageView like this
var path = UIBezierPath()
path.moveToPoint(CGPointMake(20, 30))
path.addLineToPoint(CGPointMake(40, 30))
// add as many coordinates you need...
path.closePath()
var layer = CAShapeLayer()
layer.path = path.CGPath
layer.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.5).CGColor
layer.hidden = true
bodyImage.layer.addSublayer(layer)
Than I overrided the touchesbegan function in order to show and hide when the shapes are tapped.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first! as? UITouch {
// get tapped position
let position = touch.locationInView(self.bodyImage)
// loop all sublayers
for layer in self.bodyImage.layer.sublayers! as! [CAShapeLayer] {
// check if tapped position is inside shape-path
if CGPathContainsPoint(layer.path, nil, position, false) {
if (layer.hidden) {
layer.hidden = false
}
else {
layer.hidden = true
}
}
}
}
}

Draw straight line in Swift with Sprite Kit, creating multiple lines

I'm trying to make a game in iOS, using Swift and Sprite Kit. I have the following bit of codes, but it's creating multiple lines. What I want to do is to create a single line, end of which will follow the tip of the finger of the user as the user drags the finger across the screen until the he or she takes the finger off the screen, then for the line to remain there. I found a similar question on stack overflow at Drawing straight line with spritekit and UITouch creates multiple lines, but it is written in Objective-C. And I don't think I understood the answer entirely to be honest. I'm using Xcode 7 and Swift 2.
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
}
let path = CGPathCreateMutable()
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let position1 = touch!.locationInNode(self)
CGPathMoveToPoint(path, nil, position1.x, position1.y)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let position2 = touch!.locationInNode(self)
CGPathAddLineToPoint(path, nil, position2.x, position2.y)
CGPathCloseSubpath(path)
let line = SKShapeNode()
line.path = path
line.strokeColor = UIColor.blackColor()
line.lineWidth = 5
self.addChild(line)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Any thoughts or suggestions would be greatly appreciated. Thanks.
Ryan
I may be wrong because I don't know too much about game development with Swift. But it appears you are creating a line every time you more your finger, have you tried creating the line in touchesEnded?
Did you try your code without the line
CGPathCloseSubpath(path)
According to the documentation, this is what it does:
Appends a line from the current point to the starting point of the
current subpath and ends the subpath.
and I don't think you want to have an additional line from your last touch to the start of the line with every new touch. Closing of a CGPath is only needed if you want a line that ends where it started.
I would cheat to do this:
Create a very thin sprite, in the line colour you want, and stretch its end point to where you want it to go.
This is effectively a rectangular box made out of an SKSpriteNode that's stretched from the origin to the current point of touch.
Rotating and then stretching a SKSpriteKit node is best done (for me) by attaching it to an SKNode, and rotating the node as needed, then stretching the nested SKSpriteNode as far as is needed to reach the user's current touch point.
Put the origin of the SKNode and the SKSpriteNode, at the same place, the middle left edge, and rotate around that. Or whatever works for you mathematically... This is makes the most sense to me, but it could be the centre points of any edge of the rectangle and you then stretch accordingly.

How do I detect if there is a tap on right or left side of the iPhone screen?

I'm a fairly new beginner into the iOS world, so forgive me if I leave out some details or if I'm not being clear enough. I have a ball placed on the screen at the bottom and would like to know how to make it go left if the user taps on the left half of iPhone and go right if the user taps on the right half of the iPhone.
The code that I'm trying to make work is this:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationOfTouch(<#touchIndex: Int#>, inView: <#UIView?#>)
}
ball!.physicsBody!.applyImpulse(CGVectorMake(25.0, 40.0))
}
I know there is code missing, but I can't seem to understand how to approach it. Am I doing this right? I will deeply appreciate your help.
so I did figure out the code. This is what I did:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
var touch = touches.first as! UITouch
var point = touch.locationInView(self.view)
if point.x < size.width / 2 {
ball!.physicsBody!.applyImpulse(CGVectorMake(-5.0, 10.0))
}
else {
ball!.physicsBody!.applyImpulse(CGVectorMake(5.0, 10.0))
}
}
Now, I'm coming across another problem, which might not be as complicated as I'm thinking to solve it. So, initially the ball is stationary when the app launches, and it goes in (-5,10) direction if tapped left, and (5,10) if tapped right. The problem is, when I tap right, when the app starts, it goes in (5,10) direction, but it doesn't go in left in the same direction. If I tap on right first when app launches and ball starts moving towards (5,10) direction, I want it to move left in the exact same direction from which it started while moving forward, almost in like a zig zag format. Something like this format /V, if you were to look at that in portrait view, except the line will be the ball going left and right. I hope it makes sense :)
I will keep trying to figure it out and hopefully have it figured out by the time you read it.
I'm also fairly new so I don't know of a more advanced solution.
What I would do is draw/add a line in the center of the screen. For example, I would use a SKSpriteNode and place it in the center of the screen.
var middleLine = SKSpriteNode(imageNamed: "CenterLine")
middleLine.alpha = 0 //you don't want the line to show
middleLine.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
This would place the line sprite at the center of the screen. And then, inside the touchesBegan, I would make an if statement concerning if the tap is less than the y coordinate of the center line or greater. If it's less, then the tap would be on the left, if it's greater than the y coordinate, the tap would be on the right.
You would need to make it return the location of the touch where the user tapped in order to compare.
EDIT: To make it easier, you don't even have to add the sprite, just compare the touch x and y to the CGRectGetMidX(self.frame) and CGRectGetMidY(self.frame)
I used this in my game when figuring out if an object was leaving the screen. I compared its x,y coordinates if it was greater than the coordinates inside the frame (or less than).

Resources