How do I give screenshot file a filename when sharing via UIActivityView - swift

I have created a VC with a print and share friendly version of a bunch of calculations. When I press "share" there appears the little icon and all the share options which is great. I cannot figure out how to add a filename of some kind beside the little icon. I think this would look much more professional if I could get this accomplished.
Hope there is a simple solution someone could help with :)
Here is my code:
import UIKit
class EvenPrintableViewController: UIViewController {
#IBOutlet weak var widthSizeTransfer: UILabel!
#IBOutlet weak var heightSizeTransfer: UILabel!
#IBOutlet weak var lengthTransfer: UILabel!
#IBOutlet weak var calcOutput: UILabel!
// Instantiate variables for Even transfer
var largeSizeRelay: String?
var lengthSizeRelay: String?
var heightRelay: String?
var calcOutputRelay: String?
override func viewDidLoad() {
super.viewDidLoad()
// Sets share icon to share/print view
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareTapped))
// Assign labels to Metric Even VC values via instances above
widthSizeTransfer.text = witdhSizeRelay
heightSizeTransfer.text = heightSizeRelay
heightTransfer.text = heightRelay
calcOutput.text = calcOutputRelay
}
// Share function for share button
#objc func shareTapped() {
let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { ctx in
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
}
let vc = UIActivityViewController(activityItems: [image], applicationActivities: [])
vc.excludedActivityTypes = [.assignToContact, .addToReadingList]
vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
present(vc, animated: true)
}
}

First save the UIImage as a temporary png/jpg file:
guard let imageData = image.pngData() else { return }
Then save it as a temporary file, which lets you to choose a file name:
let tempDir = FileManager.default.temporaryDirectory
let imgFileName = "YOUR_IMG_FILE_NAME.png"
let tempImgDir = tempDir.appendingPathComponent(imgFileName)
try? imageData.write(to: tempImgDir)
Then you can share the URL instead:
// Your code
let vc = UIActivityViewController(activityItems: [tempImgDir], applicationActivities: [])
P.S. the file is only temporary.

Related

Xcode, adding my image view to mail composer in app

I am hoping someone can help me with something I've not done before. which is attach an image from a image view and put it into my email in app. i have all other fields working correctly I just cannot add my image.
thanks in advance for help
class SecondViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var imageView: UIImageView!
func showMailComposer() {
guard MFMailComposeViewController.canSendMail() else {
return
}
let composer = MFMailComposeViewController()
composer.mailComposeDelegate = self
composer.setToRecipients(["LJDNSGKJNDGJ"])
composer.setSubject("JSABFKASJ")
composer.setMessageBody("hbdfnjbqeashfbnwdlskm", isHTML: false)
//I would like to know how to connect the "#IBOutlet var imageView: UIImageView!" to the composer. here ? and this would then present the image in the email.
)
present(composer, animated: true)
func mailButtonPress() {
if let image = imageView!.image {
composeMail(with:image)
} else {
print("image is nil")
}
}
func composeMail(with image:UIImage) {
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.addAttachmentData(image.jpegData(compressionQuality: CGFloat(1.0))!, mimeType: "image/jpeg", fileName: "test.jpeg")
mailComposeVC.setSubject("Email Subject")
mailComposeVC.setMessageBody("<html><body><p>This is your message</p></body></html>", isHTML: true)
self.present(mailComposeVC, animated: true, completion: nil)
}

Unable to to install "GSImageViewerController Pod" and unable to use its code in project in swift

I need tapped image in full screen for that one of the developer suggested this GSImageViewerController pod..
if i install the pod only like pod "GSImageViewerController" this and "import GSImageViewerController" in swift file in my project
and like documentation said i have written below code
import UIKit
import GSImageViewerController
class ViewController: UIViewController {
#IBOutlet weak var tapImage: UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
tapImage.isUserInteractionEnabled = true
tapImage.addGestureRecognizer(tapGestureRecognizer)
}
#objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let imageInfo = GSImageInfo(image: tapImage.image!, imageMode: .aspectFit)
let imageViewer = GSImageViewerController(imageInfo: imageInfo)
navigationController?.pushViewController(imageViewer, animated: true)
}
}
for imageview controller i have added navigationcontroller.. so here if i tap on image then image coming in full screen.. but like documentation said here if i tap anywhere in the screen or drag out the image then i am unable to go back to original position why?? where am i wrong??? please do help
Instead of push you should do present. Below is a working example from my project.
let imageInfo = GSImageInfo(image: profileImageView.image!, imageMode: .aspectFit)
let transitionInfo = GSTransitionInfo(fromView: profileImageView)
let imageViewer = GSImageViewerController(imageInfo: imageInfo, transitionInfo: transitionInfo)
present(imageViewer, animated: true, completion: nil)

How do I reload UIScrollView containing ViewControllers to add/remove view controllers

I have a scrollView that contains a dynamic amount of WeatherViewControllers each displaying the weather data of a different city the user has saved. The user can segue from the WeatherViewControllers to a CityListViewController. Where they can add and remove cities from their list which in turn should add and remove WeatherViewControllers from the scrollView upon dismissing the CityListViewController, this is where I am running into a problem.
Currently I am trying to use a protocol to call viewDidLoad in the scrollViewController upon dismissing the CityListViewController but am getting an error:
Fatal error: Unexpectedly found nil while unwrapping an Optional
value: file)
when it gets to:
let weatherScreen = storyboard!.instantiateViewController(identifier: "View Controller") as! ViewController
Side Note: Upon initially opening the app the scrollView loads properly with all the correct WeatherViewControllers in the UIScrollView and the correct cities in the list.
class ScrollViewController: UIViewController, ScrollReloadProtocol {
func reloadScrollView() {
print("SCROLL RELOADED!!!!!*******")
self.viewDidLoad()
}
#IBOutlet weak var totalScrollView: UIScrollView!
var pages = [ViewController]()
var x = 0
var weatherScreensArray = [SavedCityEntity]()
var weatherScreenStringArray = [String]()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var horizString = "H:|[page1(==view)]"
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
//userDefaults used to keep track of which screen is which to put different cities on different viewControllers
defaults.set(0, forKey: "screenNumber")
//load cities to get number of cities saved
loadCities()
var views : [String: UIView] = ["view": view]
//create all weatherWeatherControllers
while x <= weatherScreensArray.count {
pages.append(createAndAddWeatherScreen(number: x))
weatherScreenStringArray.append("page\(x+1)")
views["\(weatherScreenStringArray[x])"] = pages[x].view
let addToHoriz = "[\(weatherScreenStringArray[x])(==view)]"
horizString.append(addToHoriz)
x+=1
}
horizString.append("|")
let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|[page1(==view)]|", options: [], metrics: nil, views: views)
let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: horizString, options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views)
NSLayoutConstraint.activate(verticalConstraints + horizontalConstraints)
}
//Function to create and add weatherViewController
func createAndAddWeatherScreen(number: Int) -> ViewController {
defaults.set(number, forKey: "screenNumber")
let weatherScreen = storyboard!.instantiateViewController(identifier: "View Controller") as! ViewController
weatherScreen.view.translatesAutoresizingMaskIntoConstraints = false
totalScrollView.addSubview(weatherScreen.view)
addChild(weatherScreen)
weatherScreen.didMove(toParent: self)
return weatherScreen
}
}
You could try something like this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let weatherScreen = storyboard.instantiateViewController(withIdentifier: "View Controller") as! ViewController
It's also probably better to use one word for the identifier: "ViewController", and give it the same name as the class. Make sure to set these values also in your actual storyboard.

How can I make this animation work?

I was trying to animate a set of images using this tutorial: https://www.geekylemon.com/animated-loading-screen. I converted the code from objective c to swift in order to implement it into another project, but it seems like it doesn't work properly.
Well, on the the storyboard are three Image Views(AnitmationimageView beeing the same with "L1.png", Loadimageview and the background image of the view controller). I wanted to run the AnitmationimageView and after it a transition to L1,2,3,4 images and after them to Loadimageview and after it to the background image. But when I run the program it only shows me the transition from AnitmationimageView to Loadimageview and the transition from Loadimageview to the background image. Hope this helps in "diagnosing" my problem.
class ViewController: UIViewController {
#IBOutlet weak var AnitmationimageView: UIImageView!
#IBOutlet weak var Loadimageview: UIImageView!
var loading_1: UIImage!
var loading_2: UIImage!
var loading_3: UIImage!
override func viewDidLoad() {
super.viewDidLoad()
AnitmationimageView.animationImages = [UIImage(named: "L1.png"), UIImage(named: "L2.png"), UIImage(named: "L3.png"), UIImage(named: "L4.png")] as? [UIImage]
AnitmationimageView.animationRepeatCount = 1
AnitmationimageView.animationDuration = 3 as CFTimeInterval
AnitmationimageView.startAnimating()
perform(#selector(self.delay1), with: nil, afterDelay: 3)
delay1()
delay2()
delay3()
}
#objc func delay1() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1.0)
AnitmationimageView.alpha = 0
UIView.commitAnimations()
perform(#selector(self.delay2), with: nil, afterDelay: 1.0)
}
#objc func delay2() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1.0)
Loadimageview.alpha = 1
UIView.commitAnimations()
perform(#selector(self.delay3), with: nil, afterDelay: 1.5)
}
#objc func delay3() {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(1.0)
Loadimageview.alpha = 0
UIView.commitAnimations()
}
}

NSUserDefault issue

I am creating a divelog app. When someone select a new dive, they will get an alert with two options: "Blank template" or "Use last dive as template".
The issue is with the later, last dive as a template.
Each dive I record the data to the NSUserDefaults. So, when someone wants last dive as a template, I just call each of the defaults and populate the tableview.
However, I am getting a nil error on the first field, the diveSiteTextfield.text, this baffles me:
Here is where the data gets saved to NSUserDefaults
As you can see, I added a print command to test to see if the diveSite field is nil, but it displays the correct data. The diveSiteTextfield.text is not nil.
import UIKit
import Parse
var diveUUID = NSUUID().UUIDString
class DiveDetails1VC: UIViewController, UITextFieldDelegate, UITableViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource
{
let userDefault = NSUserDefaults.standardUserDefaults()
#IBOutlet weak var ratingControl: DiveSiteRating!
#IBOutlet weak var diveSiteTextfield: UITextField!
#IBOutlet weak var diveDurationTextfield: UITextField!
...
func toDive2NewParse () {
let diveObject = PFObject(className: "divelog")
diveObject["diveNumber"] = diveNumberInt
diveObject["diveSite"] = diveSiteTextfield.text
diveObject["diveDuration"] = diveDurationTextfield.text
diveObject["maxDepth"] = diveMaxDepthTextfield.text
diveObject["diveDate"] = diveDateTextfield.text
diveObject["diveTime"] = diveTimeTextfield.text
diveObject["bodyOfWater"] = diveBodyOfWaterTextfield.text
diveObject["diveBuddy"] = diveBuddyTextfield.text
diveObject["diveCity"] = diveCityTextfield.text
diveObject["maxDepthSymbol"] = diveMaxDepthSymbolTextField.text
diveObject["diveCountry"] = diveCountryTextField.text
diveObject["uuid"] = "\(diveUUID)"
// diveObject["diveRating"] = ratingControl
diveObject["entryFrom"] = "Divelog"
if PFUser.currentUser()!.username == nil {
diveObject["username"] = "Not Signed in"
} else {
diveObject["username"] = PFUser.currentUser()!.username
}
diveObject.saveEventually()
userDefault.setObject(diveNumberInt, forKey: "diveNumber")
userDefault.setObject(diveSiteTextfield.text, forKey: "diveSite")
userDefault.setObject(diveDurationTextfield.text!, forKey: "diveDuration")
userDefault.setObject(diveMaxDepthTextfield.text, forKey: "diveDepth")
userDefault.setObject(diveMaxDepthSymbolTextField.text, forKey: "symbol_maxDepth")
userDefault.setObject(diveDateTextfield.text, forKey: "entryDate")
userDefault.setObject(diveTimeTextfield.text, forKey: "entryTime")
userDefault.setObject(diveCityTextfield.text, forKey: "diveCity")
userDefault.setObject(diveCountryTextField.text, forKey: "diveCountry")
userDefault.setObject(diveBodyOfWaterTextfield.text, forKey: "bodyOfWater")
userDefault.setObject(diveBuddyTextfield.text, forKey: "diveBuddy")
userDefault.setObject(diveUUID, forKey: "uuid")
userDefault.synchronize()
print("DiveSite is ...\(userDefault.objectForKey("diveSite"))")
}
Here is the UIAlertAction that retrieves the "last dive":
#IBAction func addNewDive (sender: AnyObject) {
let alertController = UIAlertController(title: "New Dive", message: "Choose a template", preferredStyle:UIAlertControllerStyle.ActionSheet)
let buttonOne = UIAlertAction(title: "Blank template", style: .Default, handler: { (action) -> Void in
self.performSegueWithIdentifier("segueNewDive1", sender: self)
print("Button One Pressed")
})
let buttonTwo = UIAlertAction(title: "Use last dive as template", style: .Default, handler: { (action) -> Void in
self.VC1.diveSiteTextfield.text = self.userDefault.stringForKey("diveSite")
self.VC1.diveDurationTextfield.text = self.userDefault.stringForKey("diveDuration")
self.VC1.diveMaxDepthTextfield.text = self.userDefault.stringForKey("diveDepth")
...
self.DNo.textView.text = self.userDefault.objectForKey("diveNotes") as? String;
self.userDefault.synchronize()
self.performSegueWithIdentifier("segueNewDive1", sender: self)
any help on understanding why the nil will be greatly appreciated.
Updated with Vladian's comment