drawing and moving image above uiimageview - Swift - ios

I am trying to implement simple Image manipulation in Swift, I want to draw above the image of UIImageView.
So The interface will be as it is in the following picture:
when clicking on the Emoji downside, i want to drag it and drop it on the imageview, or only clicking will move it to the uiimageview,
Then it can be moved around inside the uiimageview and save the whole image to galery.
I could not find useful source about this on google.
so Where to start with this?

If the emoji is a UIImageView, you can implement touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?). The following is where mainImageView is the view in which you want to add the emoji.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = event?.allTouches()?.first
let touchLocation = touch?.locationInView(self.view)
if(CGRectContainsPoint(emojiImageView?.frame, touchLocation)) {
//your emoji imageView has been selected.
addImageviewToMainImageView(emojiImageView)
}
}
func addImageviewToMainImageview(imageView: UIImageView!) {
imageView.removeFromSuperView()
let origin = CGPoint(mainImageView.center.x , mainImageView.center.y)
let frame = CGRect(origin.x, origin.y, imageView.frame.size.width, imageView.frame.size.height)
imageView.frame = frame
mainImageView.addSubview(imageView)
}
If you want to move the emojiImageView around within the mainImageView, you should subclass UIView to implement touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) and touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) in a similar fashion.
1) Detect the touch with touchesBegan, determine if one of the mainImageViews subviews has been touched. Set a reference to this subview.
2) If a subview has been touched, touchesMoved will use that reference to determine the new location of the subview:
let touch = event?.allTouches()?.first
let touchLocation = touch?.locationInView(self)
selectedSubview.center = touchLocation

Use following code to combine 2 images, I am not adding code for drag and drop thing.
UIImage *mainImage = firstImage;
UIImage *smallImage = secondImage;
CGPoint renderingPoint = CGPointMake(50,50);
UIImage *outputImage = nil;
if (smallImage.size.width > mainImage.size.width || smallImage.size.height > mainImage.size.height)
{
return smallImage;
}
UIGraphicsBeginImageContext(firstImage.size);
[firstImage drawAtPoint:CGPointMake(0,0)];
[secondImage drawAtPoint:renderingPoint];
outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
The outputImage here is output of 2 combined images. The renderingPoint is the Point at which you want to start drawing other image.
Just Add touches methods and get the point at which Touch ends, keeping that point as center point and by using smallImage's width, you can calculate its rendering point.
Also in keep in mind that here renderingPoint is with respect to original size of image, not the size of imageview, so make calculation accordingly to scale up or down to imageview.

Related

How to create an image from another imageview's bounds in swift

I want to create a crop feature in swift. It will display one giant image view with the image to be cropped. Then on top of it another image view with a solid boarder and transparent background which is roughly 1/3 of the giant image view.
The user will be allowed to drag that overlay image view around and portion it on the part of the giant image view they want to crop.
Then when the click crop button I want to grab only the portion of the underlying giant image view that the overlay image view is covering. I'm not quite sure how to do that.
Here is what I've tried so far and all it does it crop the top portion of the giant image view to the bounds of the over lay image view. But how can I change it so that it does the crop with the proper bounds as it already does, but with the correct portion of the giant image view. Right now it only crops the top portion of it for some reason.
#IBOutlet weak var overlayImage: UIImageView!
#IBOutlet weak var imageView: UIImageView!
var lastLocation = CGPoint()
override func viewDidLoad() {
super.viewDidLoad()
//drawCustomImage simply creates a transparent background and dashed bordered box to display on the top 1/3 of the giant image view
let image = drawCustomImage()
overlayImage.image = image
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first{
self.lastLocation = touch.locationInView(self.view)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first{
let location = touch.locationInView(self.view)
//don't let the user move the overlay image view passed the bounds of the giant image view
if(((location.y - self.lastLocation.y) + self.overlayImage.center.y) < (self.imageView.frame.maxY - (self.overlayImage.frame.height / 3)) && ((location.y - self.lastLocation.y) + self.overlayImage.center.y) > (self.imageView.frame.minY) + (self.overlayImage.frame.height / 3)){
self.overlayImage.center = CGPoint(x: self.overlayImage.center.x, y: (location.y - self.lastLocation.y) + self.overlayImage.center.y)
}
}
}
#IBAction func cropBtn(sender: AnyObject) {
let imageRef: CGImageRef = CGImageCreateWithImageInRect(imageView.image!.CGImage, overlayImage.bounds)!
imageView.bounds = overlayImage.bounds
imageView.image = UIImage(CGImage: imageRef)
overlayImage.hidden = true
}

Rotate view by dragging

I have been trying to implement an animation of sorts where a view rotates about a point when the user drags across the screen. I have implemented the part of it that controls the rotating (the part pertaining to this question). You can view all the code I have here if you would like to (it's short).
The code that controls the rotation is mainly in touchesBegan and touchesMoved:
var p = CGPoint.zero
// ...
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
p = (touches.first?.location(in: self))!
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let dev = p.x - (touches.first?.location(in: self).x)!
let angle = 2 * CGFloat(M_PI) - atan(dev / p.y)
self.transform = CGAffineTransform(rotationAngle: angle)
}
Now here is the problem: when my finger drags below the initial middle of the view (the middle before any rotation), it works perfectly fine; however, when my finger drags above the initial middle of the view, the view is rotated to the wrong amount, and it jumps back and forth between two positions really fast, so it looks like there is a copy of the view.
I don't know if it is not working because of my general math/logic or with my implementation.
Why does it not work correctly when I drag above the initial middle of the view, and how can I fix it?

Scrollable UITableView slide up to top of screen in Swift

I am trying to create a very simplified layout, something like Stripe's iOS app has which you can see here: https://stripe.com/img/dashboard_iphone/screencast.mp4
At around 0:06s the table view is swiped up and it moves up to the top of the window.
Are there any simple instructions in Swift that show this design pattern I see it everywhere but no idea how to create it
Add a UIView
Subclass that UIView with a custom class
In you custom UIView, you'll need a couple of variables and a few overrides. Make sure that user interaction is enabled on the UIView in your storyboard, then in your custom class add:
var startPosition: CGPoint?
var originalHeight: CGFloat?
After that, add the following:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
startPosition = touch?.locationInView(self)
originalHeight = self.frame.height
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let endPosition = touch?.locationInView(self)
let difference = endPosition!.y - startPosition!.y
let newFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y + difference, self.frame.width, self.frame.height - difference)
self.frame = newFrame
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
In UIScrollView.h:
// When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its `scrollsToTop` property is YES, its delegate does not return NO from `shouldScrollViewScrollToTop`, and it is not already at the top.
// On iPhone, we execute this gesture only if there's one on-screen scroll view with `scrollsToTop` == YES. If more than one is found, none will be scrolled.
var scrollsToTop: Bool // default is YES.
Initialize your scroll view delegate (unless you already have, probably in your viewDidLoad), and then set this to true.
Like this:
myScrollView.scrollsToTop = true
If you want to be sure your scroll view delegate allows this, check this method from UIScrollViewDelegate's protocol:
optional func scrollViewShouldScrollToTop(scrollView: UIScrollView) -> Bool // return a yes if you want to scroll to the top. if not defined, assumes YES
Please comment any concerns.

UIScrollView Not Scrolling All The Way Up/Down

I am currently using SpriteKit + UIScrollView + SKCameraNode to create a scrolling game. I am currently trying to reverse the direction of the UIScrollView in the vertical direction, as the scroll view seems to do it backwards from what is intuitive.
My solution to this was to put the contentOffset from the start for the scroll view to the max height, and set the camera's position to the y position in the other direction.
However, the scrolling stops halfway down at (0, 320) when it should go to (0, 0).
Here is the code for the scroll view:
let contentSize = CGSize(width: 1575, height: 760) //adjust depending on level
self.height = contentSize.height
scrollView.contentSize = contentSize
scrollView.contentOffset = CGPointMake(0, contentSize.height / 2)
Here is the code when the scroll view scrolls:
let contentOffset = CGPointMake(scrollView.contentOffset.x, self.height - scrollView.contentOffset.y)
self.gScene.setContentOffset(contentOffset)
And here is the code for setting the content offset:
self.camera!.position = CGPointMake(ogPos.x + contentOffset.x, ogPos.y + contentOffset.y)
So the camera works and scrolls in the correct direction now; however, the scrolling's content offset gets stuck at (0, 320) for no reason, and it refuses to scroll further down. If you have any ideas I'd love to hear them! Thanks!
EDIT: I also tried making the UIScrollView's contentSize with a negative height, but then it cannot scroll at all.
I just discovered that it stops short by the size of the view.
It is not a good idea to mix UIKit and SpriteKit a lot, because they work differently (different positions, different units, etc).
If you want to drag the MainScene around, you can do this:
In our MainScene we create:
let background:SKSpriteNode = SKSpriteNode(imageNamed: "background")
var lastTouch : CGPoint?
We will add background to our scene, and every SKNode as a child to this background (platforms, the player, or whatever you want to show).
Then, in touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent), we want to get the user touch and move this background depending in the user touch movement. A basic implementation would be:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
var touch : UITouch = touches.first as! UITouch
lastTouch = touch .locationInNode(self)
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch moves */
var touch : UITouch = touches.first as! UITouch
var touchLocation : CGPoint = touch .locationInNode(self)
//We uptade the background position
background.position = CGPointMake(background.position.x + (touchLocation.x - lastTouch!.x), background.position.y + (touchLocation.y - lastTouch!.y))
//We update the lastTouch
lastTouch = touchLocation;
}
If you wanted to move automatically the MainScene, you should move background in the update: method.
I discovered that it was stopping short by the size of the view's frame. I fixed the issue by simply adding an inset the size of the view's frame so it goes that much farther.

Checking background color of view in swift

Say for example I have a white background, then on every time the view is touched, a blue box sized (60x60) is added to the screen. If i keep tapping all over the screen until the entire view becomes blue, how can I use code to notify the user using for example an alert controller saying that the view has now changed color completely.
if that made sense to anyone, I would appreciate any suggestions :)
As others have stated, the best approach is to hold a reference to a 2D array to correlate with the UI. I would approach this by first:
1) Create a subclass of UIView called overlayView. This will be the view overlay on top of your View Controllers' view. This subclass will override init(frame: CGRect). You may implement a NxM grid on initialization. You will also create and add the subviews as appropriate.
Example:
let boxWidth: CGFloat = 60
let boxHeight: CGFloat = 60
let boxFrame: CGRect = CGRectMake(0, 0, 600, 600)
override init(frame: CGRect) {
super.init(frame: boxFrame)
for i in 1 ... 10 { //row
for j in 1...10 { //column
let xCoordinate: CGFloat = CGFloat(CGFloat(i) * boxWidth)
let yCoordinate: CGFloat = CGFloat(CGFloat(j) * boxHeight)
let boxFrame: CGRect = CGRect(x: xCoordinate, y: yCoordinate, width: boxWidth, height: boxHeight)
var subView: UIView = UIView(frame: boxFrame)
subView.backgroundColor = UIColor.greenColor()
self.addSubview(subView)
}
}
}
2) Override touchesBegan(touches: NSSet, withEvent event: UIEvent) within overlayView. The implementation should look something like this:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch: UITouch = touches.anyObject() as UITouch
let touchLocation: CGPoint = touch.locationInView(self)
for subView in self.subviews {
if(CGRectContainsPoint(subView.frame, touchLocation)) {
subView.removeFromSuperview()
}
}
}
2a) You will also want to create a function to notify your 2D array that this subview as been removed. This will be called from within your if statement. In addition, this function will detect if the array is empty (all values set to false)
OR
2b) if you do not need a reference to the model (you do not care which boxes are tapped only that they're all gone), you can skip 2a and check if self.subviews.count == 0. If this is the case, you do not need a 2D array at all. If this condition passes, you can present an alert to the user as needed.
3) Create an overlayView in your main View Controller and add it as a subview.

Resources