sending image from popover to parent view - xcode

I have a view that opens another view Controller as popover
the popover uses an image picker and displays the chosen image in an imageView.
The parent also has an imageView with an IBoutlet named profiler and before dismissing the popover i would like the parent view to get the chosen image.
How would i go about accessing parent and sending the image from the popover to the parent view
below is code from the popover view controller:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
picker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - Delegates
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage //2
myImageView.contentMode = .scaleAspectFit //3
myImageView.image = chosenImage //4
myImageView.layer.borderWidth = 1
myImageView.layer.masksToBounds = false
myImageView.layer.borderColor = UIColor.black.cgColor
myImageView.layer.cornerRadius = myImageView.frame.height/4
myImageView.clipsToBounds = true
dismiss(animated:true, completion: nil) //5
}
thanks for any help rendered

Use a callback closure, it's less effort than delegate/protocol
In the popover view controller add a property
weak var callback : ((UIImage) -> ())?
Call it in didFinishPickingMediaWithInfo before dismiss
callback?(chosenImage)
In the parent view controller after creating the controller add
popoverViewController.callback = { image in
// do something with the image
}
popoverViewController is the popover view controller instance

you should create protocol
protocol PopOverImagePickerDelegate: NSObjectProtocol {
func didSelect(image: UIImage)
}
inside your PopoverViewController create
weak var delegate: PopOverImagePickerDelegate?
before navigating to PopoverViewController from ParentViewController set
popOverViewController.delegate = self
and then create
extension ParentViewController: PopOverImagePickerDelegate {
func didSelect(image: UIImage) {
//do stuff
}
}
and when image picked inside PopoverViewController just call
self.delegate?.didSelect(image: image)

Related

Additional view in NSCollectionViewItem pauses dragEvent in CollectionViewController

I am trying to implement drop delegates on a NSCollectionViewController and having issues using a custom NSCollectionViewItem with an additional View Layer I've added onto the CollectionView Item. FWIW, The additional view is used draw a dashed border to indicate a drop area.
The drag event works fine on this collectionItem, and all other collectionItems without this view when it is hidden, but as soon as the drag event occurs on top of this view, the drag event pauses.
The drag event resumes as soon as the mouse is dragged outside of the view, but nothing happens if I release the drag while the mouse is over the view.
I would love to know what is happening here and how to prevent the custom view from "stealing" the mouse event from the CollectionViewContoller.
Delegate Method on DropViewController
func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
print("1")
if proposedDropIndexPath.pointee.item <= self.destinationDirectoryArray.count {
if proposedDropOperation.pointee == NSCollectionView.DropOperation.on {
return .move
}
} else if proposedDropIndexPath.pointee.item == self.destinationDirectoryArray.count {
//There's some stuff here validating the URL removed for brevity. It works okay when the focus is outside the view, but happy to add back in if helpful
if proposedDropOperation.pointee == NSCollectionView.DropOperation.on {
return .move
}
}
return[]
}
Configuring Collection View
func configureCollectionView() {
let flowLayout = NSCollectionViewFlowLayout()
flowLayout.minimumInteritemSpacing = 8.0
flowLayout.minimumLineSpacing = 8.0
destinationCollectionView.delegate = self
destinationCollectionView.dataSource = self
destinationCollectionView.register(NSNib(nibNamed: "DestinationCollectionItem", bundle: nil), forItemWithIdentifier: directoryItemIdentifier)
destinationCollectionView.collectionViewLayout = flowLayout
destinationCollectionView.registerForDraggedTypes([.fileURL])
destinationCollectionView.setDraggingSourceOperationMask(NSDragOperation.move, forLocal: true)
}
Collection View Item Setup
class DestinationCollectionItem: NSCollectionViewItem {
#IBOutlet weak var backgroundLayer: NSView!
override func viewDidLoad() {
super.viewDidLoad()
self.highlightState = .none
view.wantsLayer = true
view.layer?.cornerRadius = 8.0
backgroundLayer.isHidden = true
}
}
Custom Border View - Applied custom class in Xib and linked to File's Owner
class BorderedView: NSView {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
let path : NSBezierPath = NSBezierPath(roundedRect: self.bounds, xRadius: 10.0, yRadius: 10.0)
path.addClip()
let dashHeight: CGFloat = 2
let dashLength: CGFloat = 7
let dashColor: NSColor = .lightGray
// setup the context
let currentContext = NSGraphicsContext.current!.cgContext
currentContext.setLineWidth(dashHeight)
currentContext.setLineDash(phase: 0, lengths: [dashLength])
currentContext.setStrokeColor(dashColor.cgColor)
// draw the dashed path
let cgPath : CGPath = CGPath(roundedRect: NSRectToCGRect(self.bounds), cornerWidth: 10.0, cornerHeight: 10.0, transform: nil)
currentContext.addPath(cgPath)
currentContext.strokePath()
}
}
Well - I solved this one pretty quick.
While I previously tried adding unregisterDraggedTypes() to the backgroundLayer, the issue turned out to also be occurring on the image layer. I applied it to both the Image and backgroundLayer and it works now.
Collection View Item Setup
class DestinationCollectionItem: NSCollectionViewItem {
#IBOutlet weak var backgroundLayer: NSView!
override func viewDidLoad() {
super.viewDidLoad()
self.highlightState = .none
view.wantsLayer = true
view.layer?.cornerRadius = 8.0
backgroundLayer.isHidden = true
backgroundLayer.unregisterDraggedTypes()
self.imageView?.unregisterDraggedTypes()
self.textField?.unregisterDraggedTypes()
}
}

Saving UIImageView Locally

Right now I am able to have the user successfully take a picture using the camera and have their picture be uploaded into a imageview. However, if the user leaves that view controller when they eventually return the photo is no longer in that imageview. Is there anyway I am able to save the photo so that once a picture is taken and put into that imageview it is there until the user takes a different picture to replace it?
import UIKit
class ArsenalViewController: UIViewController,
UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var ball1: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addPhoto1(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
ball1.contentMode = .scaleToFill
ball1.image = pickedImage
}
picker.dismiss(animated: true, completion: nil)
}
First you need to save the image data somewhere (i.e. UserDefaults, Core Data, a database) and then retrieve it. UserDefaults is easy, try this:
//Encoding
let imageData:NSData = UIImageJPEGRepresentation(pickedImage!)! as NSData
//Saved image
UserDefaults.standard.set(imageData, forKey: "savedImage")
//Decode
if let data = UserDefaults.standard.object(forKey: "savedImage") as! NSData{
myImageView.image = UIImage(data: data as Data)
}
Encoding and saving image should happen right after updating your image and decoding should be done once the view has loaded all of its elements (viewDidAppear method).
After encoding and saving the image once, you can decode it anytime, even if the user left the VC and came back.

Reuse Code to set image

i´m developing an app that has a lot of view controllers and did set the back ground image with code, but i have to copy and paste that block of code in every view controller, how can i type it once and call it to reuse the code in every view controller..Thanks A lot.
var imageView: UIImageView!
let image = UIImage(named: "backGroundImage.png")!
override func loadView() {
super.loadView()
self.imageView = UIImageView(frame: CGRectZero)
self.imageView.contentMode = .ScaleAspectFill
self.imageView.image = image
self.view.addSubview(imageView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.imageView.frame = self.view.bounds
}
What you can do is make a parent UIViewController class and have all of your view controllers inherit from that class. Somethig like this:
class MyParentViewController: UIViewController {
var imageView: UIImageView!
let image = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
self.imageView = UIImageView(frame: CGRectZero)
self.imageView.contentMode = .ScaleAspectFill
self.imageView.image = image
self.view.addSubview(imageView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.imageView.frame = self.view.bounds
}
}
And then your child view controllers that enherit from this class would look something like this:
class MyViewController: MyParentViewController {
overide func viewDidLoad() {
image = UIImage(named:"My image name")
super.viewDidLoad()
}
}
Now, here is really the way you should do it
However, having multiple view controllers that are all the same probably isnt a good idea. I would just keep only the parent view controller (rename it obviously) and just change the value of "image" in the segue that leads to the view to whatever image you want. This would eliminate the need to have a ton of view controllers, and will make it easier to add more images in the future if you want.
Here's how I would do it:
protocol ImageViewBackground {
var backgroundImageView: UIImageView? {get set}
mutating func setBackgroundImage(image: UIImage)
}
extension ImageViewBackground where Self: UIViewController {
mutating func setBackgroundImage(image: UIImage) {
let backgroundImageView = self.backgroundImageView ?? setupImageView()
backgroundImageView.image = image
}
mutating func setupImageView() -> UIImageView {
let imageView = UIImageView(frame: self.view.frame)
imageView.contentMode = .ScaleAspectFill
view.addSubview(imageView)
backgroundImageView = backgroundImageView
return imageView
}
}
Then just make any UIViewController adhere to the protocol like so:
class ViewController: UIViewController, ImageViewBackground {
var backgroundImageView: UIImageView?
}
Then you can call setBackgroundImage from anywhere in your VC without having to make a generic subclass just for the background image.

How to change default grey color of tab bar items?

I tried to change default grey color of Tab Bar items, but Xcode finds error. I used some code, that code is:
import UIKit
extension UIImage {
func makeImageWithColorAndSize(color: UIColor, size: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(CGRectMake(0, 0, size.width, size.height))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
class SecondViewController: UIViewController {
let tabBar = UITabBar()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
UITabBar.appearance().selectionIndicatorImage = UIImage().makeImageWithColorAndSize(UIColor.blueColor(), size: CGSizeMake(tabBar.frame.width/CGFloat(tabBar.items!.count), tabBar.frame.height))
}
So I put this in SecondViewController just as test, and when I run application on Xcode Simulator it crash and it show error in logs (console) fatal error: unexpectedly found nil while unwrapping an Optional value
I think problem is here:
UITabBar.appearance().selectionIndicatorImage = UIImage().makeImageWithColorAndSize(UIColor.blueColor(), size: CGSizeMake(tabBar.frame.width/CGFloat(tabBar.items!.count), tabBar.frame.height))
Because when I delete this part of code, error doesn't happen.
Can someone help me ?
The problem in your code that you create UITabBar object like let tabBar = UITabBar() and this object has no relation to the tabs which are located on the form. Your tabBar is a new empty object that contains no one UITabBarItem objects and when you call this:
UITabBar.appearance().selectionIndicatorImage = UIImage().makeImageWithColorAndSize(UIColor.blueColor(), size: CGSizeMake(tabBar.frame.width/CGFloat(tabBar.items!.count), tabBar.frame.height))
the error occurs when you try to do this: tabBar.items!.count. You're trying to unwrap optional items array [UITabBarItem]? and it nil becouse tabBar is empty object and have no items.
To fix this you need to get reference to UITabBar from current UITabBarController for example like this:
class SecondViewController: UIViewController {
var tabBar: UITabBar?
override func viewDidLoad() {
super.viewDidLoad()
tabBar = self.tabBarController!.tabBar
tabBar!.selectionIndicatorImage = UIImage().makeImageWithColorAndSize(UIColor.blueColor(), size: CGSizeMake(tabBar!.frame.width/CGFloat(tabBar!.items!.count), tabBar!.frame.height))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Button to load different page in same webView

I have a webview loading a local HTML page after pressing a button in a view controller. How would I put a button under the webview to load different content in the same web view?
ViewController has no extra code entered just a button in storyboard with a present modal segue to the webView controller
webView has the following code.
//
// WebViewer.swift
// TestWebView
//
// Created by Colin McGarry on 13/03/15.
// Copyright (c) 2015 Colin McGarry. All rights reserved.
//
import UIKit
class WebViewer: UIViewController {
var page = "2page"
#IBOutlet weak var webView: UIWebView!
#IBAction func close(sender: AnyObject) {
println(sender.tag)
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func reLoad(sender: AnyObject) {
println(sender.tag)
page = "1page"
webView!.reload()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if let htmlFile = NSBundle.mainBundle().pathForResource(page, ofType: "html"){
let htmlData = NSData(contentsOfFile: htmlFile)
let baseURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath)
webView.loadData(htmlData, MIMEType: "text/html", textEncodingName: "UTF-8", baseURL: baseURL)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Under the webView i've placed two buttons, one to close and go back to the viewcontroller, the other I wanted to reload a different webpage in this view.
I tried an if statement with the sender.tag of the reload button but it wasn't recognised. Neither was the segue identifier from the first viewController
I found a solution from an unanswered question.
i changed my reload() function to.
#IBAction func reLoad(sender: AnyObject) {
println(sender.tag)
page = "1page"
if let htmlFile = NSBundle.mainBundle().pathForResource(page, ofType: "html"){
let htmlData = NSData(contentsOfFile: htmlFile)
let baseURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath)
webView.loadData(htmlData, MIMEType: "text/html", textEncodingName: "UTF-8", baseURL: baseURL)
}
}
I'm thinking that it would probably be better to put the repeated code in a function and call it each time.

Resources