I have a iOS Swift Project for share and save image. I try to add a long press interaction to save the image. I created the function of interaction, but I do not know how to save the image in Swift.
My code
override func viewDidLoad() {
super.viewDidLoad()
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "longPressed:")
self.view.addGestureRecognizer(longPressRecognizer)
}
func longPressed(sender: UILongPressGestureRecognizer) {
println("longpressed")
}
I would like to know how to add image in the library pictures. Thank you in advance for your response.
Use this code
import UIKit
class ViewController: UIViewController {
#IBOutlet var imageview: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageview.userInteractionEnabled = true
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "longPressed:")
longPressRecognizer.minimumPressDuration = 0.5
imageview.addGestureRecognizer(longPressRecognizer)
// Do any additional setup after loading the view, typically from a nib.
}
func longPressed(sender: UILongPressGestureRecognizer) {
UIImageWriteToSavedPhotosAlbum(imageview.image, self, "image:didFinishSavingWithError:contextInfo:", nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func image(image: UIImage!, didFinishSavingWithError error: NSError!, contextInfo: AnyObject!) {
if (error != nil) {
// Something wrong happened.
} else {
// Everything is alright.
}
}
}
try this, you should edit your question for saving image displayed in UICollectionViewCell
class ViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "longPressed:")
collectionView.addGestureRecognizer(longPressRecognizer)
}
func longPressed(sender: UILongPressGestureRecognizer) {
if (sender.state != .Ended) {
return
}
let point = sender.locationInView(self.collectionView)
let indexPath = self.collectionView.indexPathForItemAtPoint(point)
if (indexPath == nil) {
print("long press on collection view but not on a item")
} else {
let cell = self.collectionView.cellForItemAtIndexPath(indexPath!)
// save image to album
UIImageWriteToSavedPhotosAlbum(cell.imageView.image!, self, "image:didFinishSavingWithError:contextInfo:", nil)
}
}
func image(image: UIImage!, didFinishSavingWithError error: NSError!, contextInfo: AnyObject!) {
if (error != nil) {
// Something wrong happened.
print(error.localizedDescription)
} else {
// Everything is alright.
}
}
}
Related
I have a simple media player and I'm trying to make it change the artwork image as the songs change. With the code I have now it will display the artwork when you hit play but when I hit the next button to skip to the next item it stays the same unless you hit another button.
How can I make the UIImageView image change as the song media item changes?
import UIKit
import MediaPlayer
class ViewController: UIViewController {
#IBOutlet weak var coverImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
createQueue()
}
func showArt(){
coverImageView.image =
myMediaPlayer.nowPlayingItem?.artwork!.image(at: CGSize.init(width: 500, height: 500))
coverImageView.isUserInteractionEnabled = true
}
#IBAction func playButton(_ sender: UIButton) {
togglePlay(on: sender)
showArt()
}
#IBAction func backButton(_ sender: UIButton) {
back()
}
#IBAction func nextButton(_ sender: UIButton) {
skip()
}
}
My other functions are as followed:
import MediaPlayer
let myMediaPlayer = MPMusicPlayerApplicationController.systemMusicPlayer
let playDrake = MPMediaPropertyPredicate(value: "Drake", forProperty: MPMediaItemPropertyArtist, comparisonType: MPMediaPredicateComparison.equalTo)
let myFilterSet: Set<MPMediaPropertyPredicate> = [playDrake]
func createQueue() {
let drakeQuery = MPMediaQuery(filterPredicates: myFilterSet)
myMediaPlayer.setQueue(with: drakeQuery)
}
func skip() {
myMediaPlayer.skipToNextItem()
}
func back() {
if myMediaPlayer.currentPlaybackTime > 0.05 {
myMediaPlayer.skipToPreviousItem()
} else if myMediaPlayer.currentPlaybackTime < 0.05 {
myMediaPlayer.skipToBeginning()
} else {
//do nothing
}
}
func togglePlay(on: UIButton) {
if myMediaPlayer.playbackState.rawValue == 2 || myMediaPlayer.playbackState.rawValue == 0 {
on.setTitle("Pause", for: UIControlState.normal)
myMediaPlayer.play()
} else if myMediaPlayer.playbackState.rawValue == 1{
on.setTitle("Play", for: UIControlState.normal)
myMediaPlayer.pause()
} else {
// do nothing
}
}
Try loading the image asynchronously
DispatchQueue.global(qos: .background).async {
myMediaPlayer.nowPlayingItem?.artwork!.image(at: CGSize.init(width: 500, height: 500))
}
I have the following Swift code.
extension UIImageView {
func enableClickablePrint() {
let imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap)
self.isUserInteractionEnabled = true
}
func disableClickablePrint() {
// HERE
}
func toggleClickablePrint() {
// HERE
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
The problem I'm running into is how to fill out the disableClickablePrint and toggleClickablePrint functions.
I'd like to be able to do something like the following.
extension UIImageView {
var imageTap: UITapGestureRecognizer?
func enableClickablePrint() {
imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap)
self.isUserInteractionEnabled = true
}
func disableClickablePrint() {
if let theImageTap = imageTap {
self.removeGestureRecognizer(theImageTap)
imageTap = nil
}
}
func toggleClickablePrint() {
if let theImageTap = imageTap {
disableClickablePrint()
} else {
enableClickablePrint()
}
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
But of course the problem is you can't store properties in extensions like I'm wanting to do.
Anyway to achieve this? I want to try to keep this as clean as possible, without resorting to fancy tricks unless absolutely required.
Would the correct thing to do to be to convert this into a subclass of UIImageView? I'd like to try to avoid that if possible just because if I want to turn this into a framework or library or something, subclasses don't integrate as nicely into interface builder and the developer would have to add the extra step of changing the class of all their image views. Which I think would be awesome to avoid if possible.
Your problem is that you need to be able to recognize the UIGestureRecognizer you added, but you can't store it in a property.
Here's a (tested) solution that subclasses UITapGestureRecognizer to make the UIGestureRecognizer identifiable and then searches self.gestureRecognizers with first(where:) to see if one has been added:
extension UIImageView {
class _CFTapGestureRecognizer : UITapGestureRecognizer { }
private var _imageTap: _CFTapGestureRecognizer? { return self.gestureRecognizers?.first(where: { $0 is _CFTapGestureRecognizer }) as? _CFTapGestureRecognizer }
func enableClickablePrint() {
// Only enable once
if _imageTap == nil {
let imageTap = _CFTapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap)
self.isUserInteractionEnabled = true
}
}
func disableClickablePrint() {
if let theImageTap = _imageTap {
self.removeGestureRecognizer(theImageTap)
}
}
func toggleClickablePrint() {
if _imageTap == nil {
enableClickablePrint()
} else {
disableClickablePrint()
}
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
I've use this extension for years and it work not only image but with any view.
extension UIView {
func addTapGuesture(target: Any, action: Selector) {
let tap = UITapGestureRecognizer(target: target, action: action)
tap.numberOfTapsRequired = 1
addGestureRecognizer(tap)
isUserInteractionEnabled = true
}
}
Usage:
imageView.addTapGuesture(target: self, action: #selector(imageTapped))
#objc func imageTapped() {
print("Tapped")
}
You could make an extension variable using a getter/setter:
extension UIImageView {
var tap: UITapGestureRecognizer {
get {
return //the created tap
}
set(value) {
print(value)
}
}
}
Since Extensions in swift can't contain stored properties, these are the solutions:
Fisrt one is the most used workaround is to use Objective_C runtime, by using objc_getAssociatedObject and objc_setAssociatedObject functions.
OK it's a nice solution, but if there is pure swift approach to do that so why not!
In your extension, define a struct with the field that you want to use, here you want for example UITapGestureRecognizer
Tip Create this struct as private You don't need anyone to access it of course.
Then define a computed property that will use this struct....
By doing this you have achieved what you need and you don't use the Objective-C at all .
Example :
extension UIImageView {
private struct TapGestureHelper{
static var tapGestureRecognizer : UITapGestureRecognizer?
}
var imageTap: UITapGestureRecognizer?{
get {
return TapGestureHelper.tapGestureRecognizer
}
set {
TapGestureHelper.tapGestureRecognizer = newValue
}
}
func enableClickablePrint() {
imageTap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
self.addGestureRecognizer(imageTap!)
self.isUserInteractionEnabled = true
}
func disableClickablePrint() {
guard let gesture = self.gestureRecognizers?.first else {
return
}
self.removeGestureRecognizer(gesture)
self.imageTap = nil
}
func toggleClickablePrint() {
if let theImageTap = imageTap {
disableClickablePrint()
} else {
enableClickablePrint()
}
}
#objc fileprivate func imageTapped(_ sender: UITapGestureRecognizer) {
print("Image tapped")
}
}
I'm having problems trying to get a UI button to have multiple taps I know it's not ideal but if someone could show me what I'm doing wrong or point me in the right direction that would be great. Below is my current code where I'm trying to create a function called two pressed that responds based off how many times its tapped.
var resultOfLabel = ""
#IBOutlet weak var outputLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture1 = UITapGestureRecognizer(target: self, action: #selector(singleTap(gesture:)))
UIButton.addGestureRecognizer(tapGesture1)
let tapGesture2 = UITapGestureRecognizer(target: self, action: #selector(doubleTap(gesture:)))
tapGesture2.numberOfTapsRequired = 2
UIButton.addGestureRecognizer(tapGesture2)
let tapGesture3 = UITapGestureRecognizer(target: self, action: #selector(tripleTap(gesture:)))
tapGesture3.numberOfTapsRequired = 3
UIButton.addGestureRecognizer(tapGesture3)
let tapGesture4 = UITapGestureRecognizer(target: self, action: #selector(quadrupleTap(gesture:)))
tapGesture4.numberOfTapsRequired = 4
UIButton.addGestureRecognizer(tapGesture4)
// Do any additional setup after loading the view.
}
#IBAction func twoPressed(sender: UIButton) {
#objc func singleTap() {
print(“2”)
}
#objc func doubleTap() {
print(“a”)
}
#objc func tripleTap() {
print(“b”)
}
#objc func quadrupleTap() {
print(“c”)
}
resultOfLabel += "\(sender)"
outputLabel.text = resultOfLabel
}
There is no problem in that except get these 4 functions out of the IBAction method
let tapGesture1 = UITapGestureRecognizer(target: self, action: #selector(self.singleTap(_:)))
UIButton.addGestureRecognizer(tapGesture1)
//
#objc func singleTap(_ sender: UITapGestureRecognizer? = nil) {
print(“2”)
self.twoPressed(sender.View as! UIButton)
}
#objc func doubleTap() {
print(“a”)
}
#objc func tripleTap() {
print(“b”)
}
#objc func quadrupleTap() {
print(“c”)
}
#IBAction func twoPressed(sender: UIButton) {
resultOfLabel += "\(sender)"
outputLabel.text = resultOfLabel
}
I'm trying to implement HERE maps SDK gestures. I added delegate and didRecivePan function. The pan gesture is recognized by the application.
Problem is that my mapView gets frozen for the time my pan gesture is being used and it creates lagging like map scrolling which makes UX really annoying. Is there anyway this can be resolved.
var follow : Bool = true;
#IBOutlet weak var mapView: NMAMapView!
let positionManager = NMAPositioningManager.self
let gestureMarker = NMAMapMarker.self
override func viewDidLoad() {
super.viewDidLoad()
mapView.gestureDelegate = self
}
#objc func didLosePosition(){ print("Position lost")}
#objc func positionDidUpdate(){
/* Possible solution but an ugly one!
if(follow == true){
mapView.gestureDelegate = self
}else if(follow == false){
mapView.gestureDelegate = nil
}*/
print("Follow \(follow)")
print("position updated")
let position = positionManager.sharedInstance().currentPosition
print(position!.coordinates ?? "xx")
if(follow){
mapView.set(geoCenter:(position?.coordinates)!,animation: .linear)
}
}
override func viewWillAppear(_ animated: Bool) {
if(positionManager.sharedInstance().startPositioning()){
// Register to positioning manager notifications
NotificationCenter.default.addObserver(self, selector: #selector(self.positionDidUpdate), name: NSNotification.Name.NMAPositioningManagerDidUpdatePosition, object: positionManager.sharedInstance())
NotificationCenter.default.addObserver(self, selector: #selector(self.didLosePosition), name: NSNotification.Name.NMAPositioningManagerDidLosePosition, object: positionManager.sharedInstance())
}
super.viewWillAppear(animated)
mapView.zoomLevel = 17
mapView.set(geoCenter: NMAGeoCoordinates(latitude: 45.921189263505788, longitude: 14.234863696633125),
animation: .linear)
let mapMarker = NMAMapMarker(geoCoordinates: NMAGeoCoordinates(latitude: 45.921189263505788, longitude: 14.234863696633125), icon: NMAImage(uiImage: UIImage(named: "driver") ?? UIImage())!)
mapView.positionIndicator.isVisible = true;
mapView.positionIndicator.isAccuracyIndicatorVisible = true
mapView.positionIndicator.set(displayObject: mapMarker, toLayer: NMAMapLayerType.foreground)
mapView.copyrightLogoPosition = NMALayoutPosition.centerRight
}
func mapView(_ mapView: NMAMapView, didReceivePan translation: CGPoint, at location: CGPoint) {
follow = false
}
#IBAction func followButton(_ sender: UIButton) {
follow = true
mapView.set(geoCenter: (positionManager.sharedInstance().currentPosition?.coordinates)!,
animation: .linear)
mapView.zoomLevel = 17
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I have a table view with static cells.
My second section has a header but no rows, under that section I have a label that when pressed should call sendEmail() function which will open the email app on their device.
I've tried using a label, text view, button, overriding the didSelectCellForRow function and all have failed.
I'm completely lost what ouches aren't being recognized.
I've added print statements to my touchesBegan function but they never print.
What could be the issue?
import UIKit
import MessageUI
class InfoTVC: UITableViewController, MFMailComposeViewControllerDelegate{
let ownerEmail = "test#email.com"
#IBOutlet weak var contactLbl: UILabel!
// MARK: - View functions
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - IBOutlet methods
#IBAction func backBtn(_ sender: Any) {
_ = navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
}
// MARK: - Email methods
// Open users email app on device
func sendEmail(){
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients([ownerEmail])
mail.setMessageBody("<p>Hello I had the chance to use your app and </p>", isHTML: true)
present(mail ,animated: true, completion: nil)
}
else{
// Failure
print("failed to open mail")
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self.view)
if contactLbl.frame.contains(location) {
print("yes")
sendEmail()
}
else{
print("no")
}
}
}
}
try to add tap gesture recognizer instead of handing touches
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.youLabelTapped(_:)))
yourLabel.addGestureRecognizer(tapGesture)
OR alternatively: add target directly to your label
yourLabel.addTarget(self, action: #selector(self.youLabelTapped(_:)), forControlEvents: .TouchUpInside)
and you func that will be called:
func youLabelTapped(_ sender: UITapGestureRecognizer) {
print("label tapped")
}
EDIT:
REQUIRED: don't forget to set user interaction enabled:
yourLabel.isUserInteractionEnabled = true