how to overlay an image over an image in xcode? - ios

I am trying to make an app where the user can select an image out of their image library that will be used as background, followed by their logo that they can also choose from their (photo) library...
For now i haven't found a tutorial that can help me, mostly because the user must be able to set their own images instead of a default image.
Also, does anyone of you guys also know how i can have multiple UIImagePickerControllers since this code affects both images at the same time instead of one per picker?
What i use/have :
I use swift
I use xcode 7.0.1
This is
the storyboard i currently use.
My swift file :
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var logo: UIImageView!
#IBOutlet weak var bgimg: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func selectbg(sender: AnyObject) {
let bgPicker = UIImagePickerController()
bgPicker.delegate = self
bgPicker.sourceType = .PhotoLibrary
self.presentViewController(bgPicker, animated: true, completion: nil)
}
#IBAction func selectlogo(sender: AnyObject) {
let logoPicker = UIImagePickerController()
logoPicker.delegate = self
logoPicker.sourceType = .PhotoLibrary
self.presentViewController(logoPicker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
logo.image = image
bgimg.image = image
self.dismissViewControllerAnimated(false, completion: nil)
}
#IBAction func addImage(sender: AnyObject) {
let ActionAlert = UIAlertController(title: nil, message: "What image do you want to add/edit?", preferredStyle: .ActionSheet)
let bgimage = UIAlertAction(title: "Background", style: .Default, handler: { (Alert:UIAlertAction!) -> Void in
print("Edit background image")
})
let logo = UIAlertAction(title: "Logo", style: .Default) { (Alert:UIAlertAction!) -> Void in
print("Edit logo")
}
let cancel = UIAlertAction(title: "Cancel", style: .Cancel) { (Alert:UIAlertAction!) -> Void in
print("remove menu")
}
ActionAlert.addAction(bgimage)
ActionAlert.addAction(logo)
ActionAlert.addAction(cancel)
self.presentViewController(ActionAlert, animated: true, completion: nil)
}
}
If i wasn't clear about my question, feel free to ask for more info

Create two UIImageViews for each image and add the foreground one as a subview to the parent.
Something like this:
let bgimg = UIImage(named: "image-name") // The image used as a background
let bgimgview = UIImageView(image: bgimg) // Create the view holding the image
bgimgview.frame = CGRect(x: 0, y: 0, width: 500, height: 500) // The size of the background image
let frontimg = UIImage(named: "front-image") // The image in the foreground
let frontimgview = UIImageView(image: frontimg) // Create the view holding the image
frontimgview.frame = CGRect(x: 150, y: 300, width: 50, height: 50) // The size and position of the front image
bgimgview.addSubview(frontimgview) // Add the front image on top of the background

Here's the sample code for merging footer image to original
extension UIImage{
func merge(mergewith:UIImage) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let actualArea = CGRect(x: 0, y: 0, width: size.width, height: size.height)
let mergeArea = CGRect(x: 0, y: size.height - mergewith.size.height, width: size.width, height: mergewith.size.height)
self.draw(in: actualArea)
mergewith.draw(in: mergeArea)
let merged = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return merged
}
}

Related

Image/Video sharing on iOS, preparing alert progress box, what component is this in Swift library?

I always see apps that provide this "Preparing" screen to show its progress whenever I share a big video. I know Swift has UIAlertController that can show a popup, but it's bare so it leads to think that this Preparing alert box gotta be an Apple built-in framework because many other apps have the exact same UI when sharing a large asset. Anyone know what this alert box is call?
Preparing screen
There is no default dialog box to display Progress HUD. But, you can customise the UIAlertController. Even others also will do the same.
#IBAction func showPopover(_ sender: UIBarButtonItem) {
let alertTitle = "Preparing...\n\n\n\n\n"
let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .alert)
let rect = CGRect(x: 10, y: 50, width: 250, height: 110)
let customView = UIView(frame: rect)
alertController.view.addSubview(customView)
let progressLabel = ProgressLabel()
let kLabelSize = 60.0
progressLabel.frame = CGRect(origin: CGPoint(x: (customView.frame.width/2.0)-(kLabelSize/2.0), y: (customView.frame.height/2.0)-(kLabelSize/2.0)), size: CGSize(width: kLabelSize, height: kLabelSize))
progressLabel.font = .systemFont(ofSize: 12)
progressLabel.textAlignment = .center
progressLabel.layer.cornerRadius = 30
progressLabel.layer.borderColor = UIColor.gray.cgColor
progressLabel.layer.borderWidth = 3
progressLabel.layer.masksToBounds = true
customView.addSubview(progressLabel)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {(alert: UIAlertAction!) in print("cancel")})
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion:{})
updateProgress(progressLabel)
}
var progress = 1.0
func updateProgress(_ label: ProgressLabel) {
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
label.text = "\(self.progress)%"
self.progress += 1.0
if self.progress <= 100.0 {
self.updateProgress(label)
}
}
}
}
class ProgressLabel: UILabel {
var value: CGFloat = 0.0
// Create your own circle shape layer to render the progress
private var progressLayer: CAShapeLayer!
override func draw(_ rect: CGRect) {
super.draw(rect)
}
}
Note:
Here, you have to take consideration for y value of customview based on the AlertController's title and message text size.

How to add image as title in UIalertController?

I am new to iOS, I included image as title and message, both are displaying but message not properly populate. How to set message exactly below of title image, I tried but not happening. Please can anyone help me?
called in func:
CommonMethods.alertWithImage(msg:"Allow XXX to access your device's location?",
Icon: UIImage(named: "loc.png")!,
fromView: self)
Here is my code:
let alrt = UIAlertController(title:nil, message: msg, preferredStyle:.actionSheet)
alrt.setMessage(font: UIFont(name: "Poppins-medium", size: 20), color: UIColor.white)
let btn1 = UIAlertAction(title: "While using the app.", style: .default,handler: nil)
let btn2 = UIAlertAction(title: "Only this time.", style: .default,handler: nil)
let btn3 = UIAlertAction(title: "Deny", style: .default,handler: nil)
alrt.addAction(btn1)
alrt.addAction(btn2)
alrt.addAction(btn3)
alrt.view.tintColor = UIColor.blue
let subview = (alrt.view.subviews.first?.subviews.first?.subviews.first!)! as UIView
alrt.view.subviews.first?.subviews.first?.subviews.first?.backgroundColor = UIColor.black
let imageView = UIImageView(frame: CGRect(x: 180, y: 0, width: 35, height: 35))
imageView.image = Icon
alrt.view.addSubview(imageView)
fromView.present(alrt, animated: true, completion: nil)
as #Larme said, you can use a custom one ( a third party lib ).
Here is the solution of customize UIAlertController
class Alert: UIAlertController{
let offset: CGFloat = 20
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let title = getLabel(for: view){
var f = title.frame
f.origin = CGPoint(x: f.origin.x, y: f.origin.y - offset)
title.frame = f
}
}
func getLabel(for v: UIView?) -> UILabel?{
guard let vue = v else{ return nil }
var result: UILabel?
for sub in vue.subviews{
sub.clipsToBounds = false
if sub.isKind(of: UILabel.self){
return sub as? UILabel
}
else {
result = getLabel(for: sub)
if result != nil{
return result
}
}
}
return result
}
}
use like this:
let alrt = Alert(title:nil, message: msg, preferredStyle:.actionSheet)

Swift 3: Can you save the position of a cropped image and access it later when the full image is displayed?

Language: Swift 3
Task: Allow users to crop their profile image on upload
Question: Initially I was going to try and figure out to save the cropped image and the full image to my server because I need both, then came up with the question... Is there a way to save the cropped position of the full image to my mysql database(php) then access it when I need to display the cropped image?
I'm using
self.imagePicker.allowsEditing = true
To allow the users to crop photo
let chooseAction = UIAlertAction(title: "Choose Image", style: .default, handler: { (alert: UIAlertAction!) -> Void in
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) {
self.imagePicker.delegate = self
self.imagePicker.sourceType = .savedPhotosAlbum
self.imagePicker.allowsEditing = true
self.present(self.imagePicker, animated: true, completion: nil) }
})
let takeAction = UIAlertAction(title: "Take Image", style: .default, handler: { (alert: UIAlertAction!) -> Void in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
self.imagePicker.delegate = self
self.imagePicker.sourceType = .camera
self.imagePicker.allowsEditing = true
self.present(self.imagePicker, animated: true, completion: nil) }
})
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: { (alert: UIAlertAction!) -> Void in })
optionMenu.addAction(chooseAction)
optionMenu.addAction(takeAction)
optionMenu.addAction(cancelAction)
self.present(optionMenu, animated: true, completion: nil)
}
EDIT
I am saving the full image to server
I need the simplest way to get the cropped square position if possible then store the position in a variable (I will store this on my server)
On certain views when the image is displayed I only want to show the cropped part of the full image. I will retrieve the saved cropped position set on upload then only show that part of the image.
I decided to try this out since there are a few issues that can occur doing this. I made this example:
class ViewController: UIViewController {
private let scrollViewPanel: HitForwardingView = HitForwardingView()
private let scrollView: UIScrollView = UIScrollView()
private let imageView: UIImageView = UIImageView()
private var image: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
scrollViewPanel.frame = view.bounds
scrollViewPanel.listenerView = scrollView
view.addSubview(scrollViewPanel)
scrollView.frame = CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0)
scrollView.center = CGPoint(x: scrollViewPanel.bounds.midX, y: scrollViewPanel.bounds.midY)
scrollViewPanel.addSubview(scrollView)
scrollView.clipsToBounds = false
scrollView.delegate = self
scrollView.minimumZoomScale = 0.2
scrollView.maximumZoomScale = 5.0
if let image = UIImage(named: "testImage") {
setupWithImage(image)
scrollToCenter()
}
// Just some masking to make things look nicer
scrollViewPanel.addSubview({
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: scrollViewPanel.bounds.width, height: scrollView.frame.minY))
view.isUserInteractionEnabled = false
view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
return view
}())
scrollViewPanel.addSubview({
let view = UIView(frame: CGRect(x: 0.0, y: scrollView.frame.minY, width: scrollView.frame.minX, height: scrollView.frame.height))
view.isUserInteractionEnabled = false
view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
return view
}())
scrollViewPanel.addSubview({
let view = UIView(frame: CGRect(x: scrollView.frame.maxX, y: scrollView.frame.minY, width: scrollViewPanel.frame.width - scrollView.frame.maxX, height: scrollView.frame.height))
view.isUserInteractionEnabled = false
view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
return view
}())
scrollViewPanel.addSubview({
let view = UIView(frame: CGRect(x: 0.0, y: scrollView.frame.maxY, width: scrollViewPanel.bounds.width, height: scrollViewPanel.frame.height - scrollView.frame.maxY))
view.isUserInteractionEnabled = false
view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
return view
}())
// Add a trigger to show crop
view.addGestureRecognizer({
let recognizer = UITapGestureRecognizer(target: self, action: #selector(debugSnapshot))
recognizer.numberOfTapsRequired = 2
return recognizer
}())
}
#objc private func debugSnapshot() {
// Going to use relative coordinates depending on the original image. The result should be a frame normalized depending on original:
// x=0 is left-most
// x=1 is right-most
// y=0 is top-most
// y=1 is bottom-most
let convertedScrollViewFrame = scrollView.convert(scrollView.bounds, to: scrollViewPanel)
let convertedImageViewFrame = imageView.convert(imageView.bounds, to: scrollViewPanel)
var frame = convertedScrollViewFrame
frame.origin.x -= convertedImageViewFrame.origin.x
frame.origin.y -= convertedImageViewFrame.origin.y
frame.origin.x /= convertedImageViewFrame.width
frame.origin.y /= convertedImageViewFrame.height
frame.size.width /= convertedImageViewFrame.width
frame.size.height /= convertedImageViewFrame.height
print(frame)
// Do a reconstruction
let previewPanelView = UIView(frame: self.view.bounds)
previewPanelView.backgroundColor = UIColor.black.withAlphaComponent(0.8)
previewPanelView.addSubview({
let panel = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 300.0, height: 300.0))
panel.center = CGPoint(x: previewPanelView.bounds.midX, y: previewPanelView.bounds.midY)
panel.clipsToBounds = true
let imageView = UIImageView(image: self.imageView.image)
// Frame now relative to where we display it (panel)
imageView.frame = CGRect(x: -frame.origin.x * panel.bounds.width / frame.size.width,
y: -frame.origin.y * panel.bounds.height / frame.size.height,
width: panel.bounds.width / frame.size.width,
height: panel.bounds.height / frame.size.height)
panel.addSubview(imageView)
return panel
}())
view.addSubview(previewPanelView)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
previewPanelView.removeFromSuperview()
}
}
private func setupWithImage(_ image: UIImage) {
imageView.image = image
imageView.frame = CGRect(x: 0.0, y: 0.0, width: image.size.width, height: image.size.height)
scrollView.addSubview(imageView)
scrollView.contentSize = imageView.frame.size
}
private func scrollToCenter() {
scrollView.zoomScale = 1.0
scrollView.contentOffset = CGPoint(x: scrollView.contentSize.width*0.5 - scrollView.bounds.size.width*0.5,
y: scrollView.contentSize.height*0.5 - scrollView.bounds.size.height*0.5)
}
}
extension ViewController: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
}
private extension ViewController {
class HitForwardingView: UIView {
weak var listenerView: UIView?
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let original = super.hitTest(point, with: event)
if (original == self || original == nil) && self.bounds.contains(point) {
return listenerView
} else {
return original
}
}
}
}
To make it work you can simply create a new project and copy this code into your ViewController. You need a test image as well named "testImage". You can scroll your image around, zoom it in or out. If you double-tap a new overlay will appear which should show a cropped image.
Explanations:
The whole view controller is done in code just to make it easier to explain. In reality all the views would be done in storyboard with constraints.
Because we use a "small" scroll view we need to forward touch events to the scroll view even when you drag outside of it. To do so HitForwardingView is introduced. Basically it is collecting events and forwarding them to the scroll view.
Both "position" construction and deconstruction is demonstrated in debugSnapshot. To your backend you would send data from received frame in this method. You would then later use this same frame from backend to position image correctly to mimic cropped image.
I hope the rest is pretty much self-explanatory from the code. If there are any questions about it please go ahead.

Image Selected From Image Picker Not Displaying

I'm kind of lost. My Image Picker is working but the image is not displaying in my Image View. I have looked over my code and various solutions and it still is not working. I have set the delegate to self and double checked my methods and it is still not showing the image where it is supposed to.
import UIKit
class AlterProfileViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
view?.backgroundColor = UIColor.white
navigationItem.title = "Profile Settings"
view.addSubview(selectProfileImage)
///Constraints for all views will go here
_ = selectProfileImage.anchor(view.centerYAnchor, left: view.leftAnchor, bottom: nil, right: nil, topConstant: -275, leftConstant: 135, bottomConstant: 0, rightConstant: 0, widthConstant: 100, heightConstant: 100)
// selectProfileImage.layer.cornerRadius = selectProfileImage.frame.size.width/2
///////////////////////////////////////////////
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
selectProfileImage.layer.cornerRadius = selectProfileImage.frame.size.width / 2;
selectProfileImage.layer.masksToBounds = true
}
//Where all buttons and labels will be added
//will just be a nice looking image view to be next to the profile settings button
lazy var selectProfileImage: UIImageView = {
let selectPicture = UIImageView()
// self.selectProfileImage.layer.cornerRadius = self.selectProfileImage.frame.size.width / 2;
selectPicture.image = UIImage(named: "Paris")
// selectPicture.layer.cornerRadius = selectPicture.frame.size.width / 2;
selectPicture.clipsToBounds = true
selectPicture.translatesAutoresizingMaskIntoConstraints = false
selectPicture.layer.cornerRadius = selectPicture.frame.size.width/2
selectPicture.contentMode = .scaleAspectFill
selectPicture.isUserInteractionEnabled = true
selectPicture.layer.shouldRasterize = true
// will allow you to add a target to an image click
selectPicture.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView)))
selectPicture.layer.masksToBounds = true
return selectPicture
}()
func handleSelectProfileImageView() {
print("123")
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
present(picker, animated: true, completion: nil)
}
// will dispaly info of image selected
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
print("info")
var selectedImageFromPicker: UIImage?
if let editedImage = info["UIImagePickerControllerEditedImage"] as? UIImage{
print((editedImage as AnyObject).size)
selectedImageFromPicker = editedImage
}else if let originalImage = info["UIImagePickerControllerOriginalImage"] as? UIImage{
print((originalImage as AnyObject).size)
selectedImageFromPicker = originalImage
}
if let selectedImage = selectedImageFromPicker {
selectProfileImage.image = selectedImage
}
dismiss(animated: true, completion: nil)
}
// will handle the picker being closed/canceled
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
print("picker canceled")
dismiss(animated: true, completion: nil)
}
///////////////////////////////////////////////////////////////////////////////////
}

Image from View larger than device screen

I have a UIView that I created in Storyboard that I want to use in order to print a form, I have instantiated it and then i call the View and then everything goes to work, however, when this happens on a smaller screened item, such as an iPhone it cuts it off where the screen is. I have no idea where I need to adjust either the size or what in order to avoid this. Right now this is what I'm using to scale it up so I have a high quality (This issue was happening before I added the scale for quality). Should I be setting the size when I instantiate it?
func generatePDF() {
let pdfData = NSMutableData()
let bounds = self.view.bounds
UIGraphicsBeginPDFContextToData(pdfData, bounds, nil)
UIGraphicsBeginPDFPage()
guard let pdfContext = UIGraphicsGetCurrentContext() else { return }
let rescale : CGFloat = 4
func scaler(v: UIView) {
if !v.isKindOfClass(UIStackView.self) {
v.contentScaleFactor = 8
}
for sv in v.subviews {
scaler(sv)
}
}
scaler(pdfView)
let bigSize = CGSize(width: pdfView.frame.size.width*rescale, height: pdfView.frame.size.width*rescale)
UIGraphicsBeginImageContextWithOptions(bigSize, true, 1)
let context = UIGraphicsGetCurrentContext()!
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
CGContextFillRect(context, CGRect(origin: CGPoint(x: 0, y: 0), size: bigSize))
CGContextScaleCTM(context, rescale, rescale)
pdfView.layer.renderInContext(context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
CGContextSaveGState(pdfContext)
CGContextTranslateCTM(pdfContext, pdfView.frame.origin.x, pdfView.frame.origin.y)
CGContextScaleCTM(pdfContext, 1/rescale, 1/rescale)
let frame = CGRect(origin: CGPoint(x: 0, y: 0), size: bigSize)
image!.drawInRect(frame)
CGContextRestoreGState(pdfContext)
let info : UIPrintInfo = UIPrintInfo(dictionary: nil)
info.orientation = UIPrintInfoOrientation.Portrait
info.outputType = UIPrintInfoOutputType.Grayscale
info.jobName = "Work Order"
if NSUserDefaults.standardUserDefaults().URLForKey("printer") != nil {
let printer = UIPrinter(URL: NSUserDefaults.standardUserDefaults().URLForKey("printer")!)
printer.contactPrinter { (available) in
if available {
let printInteraction = UIPrintInteractionController.sharedPrintController()
printInteraction.printingItem = image
printInteraction.printInfo = info
printInteraction.printToPrinter(printer, completionHandler: { (printerController, completed, error) in
if completed {
let alert = UIAlertController(title: "Printed!", message: nil, preferredStyle: .Alert)
self.presentViewController(alert, animated: true, completion: nil)
let delay = 1.0 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), {
alert.dismissViewControllerAnimated(true, completion: {
self.dismissViewControllerAnimated(false, completion: nil)
})
})
}
})
}
}
} else {
self.dismissViewControllerAnimated(false, completion: nil)
let alert = UIAlertController(title: "Select Printer", message: "\nPlease select a printer in the More section and then try your print again", preferredStyle: .Alert)
let okayButton = UIAlertAction(title: "Okay", style: .Default, handler: nil)
alert.addAction(okayButton)
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
}
}
Try setting the boundaries of the UIView to be the boundaries of the screen like this:
let screenSize: CGRect = UIScreen.main.bounds
view.frame = CGRect(x: 0.0, y: 0.0, width: screenSize.width, height: screenSize.height)

Resources