iOS Revisited: Swift

Hot

Post Top Ad

Showing posts with label Swift. Show all posts
Showing posts with label Swift. Show all posts

27 Apr 2020

Add button programmatically using Autolayouts Swift 5 - iOS

4/27/2020 03:37:00 am 0
Creating a button using autolayouts is quite simple. In this article, I will show how to add a button programmatically and in addition to that, we will learn about all attributes like color, font, image, etc..


Add button programatically using Autolayouts Swift 5 - iOS


Create UIButton:

First of all, create a new button object of type UIButton, and also set translatesAutoresizingMaskIntoConstraints to false. Then give the auto layouts as follow:

let swiftButton = UIButton()
swiftButton.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(swiftButton)
swiftButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
swiftButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
swiftButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
swiftButton.heightAnchor.constraint(equalToConstant: 50).isActive = true


Add a title to Button:

swiftButton.setTitle("Thunder", for: .normal)

Add a title to Button:

Change button title Font & Size:

swiftButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)


Change button title Font & Size:

Change Button background color:

swiftButton.backgroundColor = UIColor.white

Change Button background color:

Change Button title color:

swiftButton.setTitleColor(UIColor.black, for: .normal)

Change Button title color:

Add image to button:

swiftButton.setImage(UIImage(named: "thunder"), for: .normal)

Add image to button:

Change image color in Button:

swiftButton.tintColor = UIColor.red


 Change image color in Button:

Space between button image and title:


swiftButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)

Space between button image and title:

Add tap action on Button:

swiftButton.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)



@objc func buttonTapped(sender: UIButton) {

    print("Button tapped")

}

Change Button title color On Tapped or Selected:

swiftButton.setTitleColor(UIColor.green, for: .highlighted)

Change Button title color On Tapped or Selected:
 

Conclusion:

As a result, we learn how to create a button programmatically & setting up all button properties.



Read More

21 Apr 2020

Dismiss multiple view controllers swift

4/21/2020 02:07:00 am 0
In order to dismiss more than one view controller, here is the small UIViewController extension that can work for many cases.

Cases like:

  • Dismiss to the particular view controller
  • Dismiss 2 or 3 or 4 or many view controllers (By count)
  • Dismiss to root view controller

Dismiss multiple view controllers swift

First of all, add this extension:

extension UIViewController {
    
    func dismissTo(vc: UIViewController?, count: Int?, animated: Bool, completion: (() -> Void)? = nil) {
        var loopCount = 0
        var dummyVC: UIViewController? = self
        for _ in 0..<(count ?? 100) {
            loopCount = loopCount + 1
            dummyVC = dummyVC?.presentingViewController
            if let dismissToVC = vc {
                if dummyVC != nil && dummyVC!.isKind(of: dismissToVC.classForCoder) {
                    dummyVC?.dismiss(animated: animated, completion: completion)
                }
            }
        }
        
        if count != nil {
            dummyVC?.dismiss(animated: animated, completion: completion)
        }
    }
    
}

Add this extension, and use it as follows...

Dismiss to particular view controller:

self.dismissTo(vc: SecondVC(), count: nil, animated: true)

Dismiss by count(1 to 100):

self.dismissTo(vc: nil, count: 3, animated: true)

Dismiss to root view controller:

self.dismissTo(vc: self.view.window?.rootViewController, count: nil, animated: true)

Finally, here is the sample project with four view controllers, download and check the example below.


Read More

16 Dec 2019

Create custom marker and custom info window in iOS using swift - Google maps

12/16/2019 09:29:00 am 10
In this article, we are going to learn about Custom Marker and Custom Info Window in Google maps.

First, create a new Xcode project and name it as Custom Marker.

In this example we are going to use completely auto layouts without a storyboard, every constraint is programmatically.

Download the sample project from the bottom of this tutorial.

Create custom marker and custom info window in iOS using swift - Google maps

Adding Google Map:

The first thing to do is integrate Google Maps SDK either using pod or other alternatives.

Here I am integrating using cocoapods.

Open terminal, go the project folder then type follow commands.

pod init

open -a xcode podfile

Then add pod 'GoogleMaps' below to the # Pods for CustomMarker.

pod install

After successful installation close the project and open workspace file.

To use google maps we need a key from google.

If you don't have one, get one from here

Okay, All set.

open AppDelegate.swift and import GoogleMaps then add the following line inside didFinishLaunchingWithOptions method:

GMSServices.provideAPIKey("YOUR API KEY")

open ViewController.swift and import GoogleMaps.

Add the following closure before viewDidLoad():

var mapView: GMSMapView = {
     let v = GMSMapView()
     v.translatesAutoresizingMaskIntoConstraints = false
     return v
 }()

Add mapView to the view as subview, add the following code inside viewDidLoad():

self.view.addSubview(mapView)
mapView.padding = UIEdgeInsets(top: 72, left: 25, bottom: 0, right: 25)
mapView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
mapView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
mapView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
mapView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
mapView.delegate = self

Don't panic with error, simply add the following extension to remove the error, we will discuss later in this example.

extension ViewController: GMSMapViewDelegate {
 
}

Now run the app, if your API key is valid you will see the map like below

Adding Google Map

Add Custom Marker:

Before creating a custom marker, first create our model, add the following model:

struct SSPlace {
    var name: String?
    var address: String?
    var coordinates: (lat: Double, lng: Double)?
}

Create array of SSPlaces as follow:

var places = [SSPlace]()

Add some sample data to places array, add the following code to the end of viewDidLoad():

places.append(SSPlace(name: "Fremont Troll", address: "N 36th St, Seattle, WA 98103, United States", coordinates: (lat: 47.651105, lng: -122.347347)))
places.append(SSPlace(name: "Grand Canyon National Park", address: "Arizona, United States", coordinates: (lat: 36.099982, lng: -112.123640)))
places.append(SSPlace(name: "Statue of Liberty National Monument", address: "New York, NY 10004, United States", coordinates: (lat: 40.689323, lng: -74.044490)))
places.append(SSPlace(name: "Yellowstone National Park", address: "United States", coordinates: (lat: 44.429311, lng: -110.588112)))
places.append(SSPlace(name: "Walt Disney World Resort", address: "Orlando, FL, United States", coordinates: (lat: 28.385280, lng: -81.563853)))

Now it's time to create a custom marker view.

Create a new swift file of type UIView and name it as CustomMarkerView. Replace the whole class with the following code:

class CustomMarkerView: UIView {
    
    var imageName: String?
    var borderColor: UIColor!
    
    init(frame: CGRect, imageName: String?, borderColor: UIColor, tag: Int) {
        super.init(frame: frame)
        self.imageName=imageName
        self.borderColor=borderColor
        self.tag = tag
        setupViews()
    }
    
    func setupViews() {
        let imgView = UIImageView()
        imgView.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(imgView)
        imgView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        imgView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        imgView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        imgView.heightAnchor.constraint(equalToConstant: 50).isActive = true
        imgView.layer.cornerRadius = 25
        imgView.layer.borderColor = borderColor?.cgColor
        imgView.contentMode = .scaleAspectFill
        imgView.layer.borderWidth = 4
        imgView.clipsToBounds = true
        imgView.image = UIImage(named: imageName!)
        
        let triangleImgView = UIImageView()
        self.insertSubview(triangleImgView, belowSubview: imgView)
        triangleImgView.translatesAutoresizingMaskIntoConstraints = false
        triangleImgView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        triangleImgView.topAnchor.constraint(equalTo: imgView.bottomAnchor, constant: -6).isActive = true
        triangleImgView.widthAnchor.constraint(equalToConstant: 23/2).isActive = true
        triangleImgView.heightAnchor.constraint(equalToConstant: 24/2).isActive = true
        triangleImgView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        triangleImgView.image = UIImage(named: "markerTriangle")
        triangleImgView.tintColor = borderColor
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

Here we are adding UIImageView to show the place image and one more UIImageView to show the bottom triangle.

Create new array to store all markers:

var markers = [GMSMarker]()

To add the places as markers on the map add the following method:

func addMarkers() {
    markers.removeAll()
    for (index, place) in places.enumerated() {
        let marker = GMSMarker()
        let customMarker = CustomMarkerView(frame: CGRect(x: 0, y: 0, width: customMarkerWidth, height: customMarkerHeight), imageName: place.name, borderColor: primaryColor, tag: index)
        marker.iconView = customMarker
        marker.position = CLLocationCoordinate2D(latitude: place.coordinates!.lat, longitude: place.coordinates!.lng)
        marker.infoWindowAnchor = CGPoint(x: 0.5, y: 0)
        marker.map = self.mapView
        marker.zIndex = Int32(index)
        marker.userData = place
        markers.append(marker)
    }
}

Add the following colors before ViewController class:

let primaryColor = UIColor(red:0.00, green:0.19, blue:0.56, alpha:1.0)

let secondaryColor = UIColor(red:0.89, green:0.15, blue:0.21, alpha:1.0)

After adding markers to the map let focus them so that users can look at those places only.

To focus the markers add the following methods:

func focusMapToShowAllMarkers() {
    if let firstLocation = markers.first?.position {
        var bounds =  GMSCoordinateBounds(coordinate: firstLocation, coordinate: firstLocation)
        
        for marker in markers {
            bounds = bounds.includingCoordinate(marker.position)
        }
        let update = GMSCameraUpdate.fit(bounds, withPadding: 20)
        self.mapView.animate(with: update)
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.focusMapToShowAllMarkers()
}

Finally call the addMarkers() function at the end of viewDidLoad():

override func viewDidLoad() {
       super.viewDidLoad()
       /***
       self.addMarkers()
}

That's it run the app, you can see markers as follows:

Create custom marke in iOS using swift - Google maps

Add Custom Info Window:

Create a new swift file of type UIView and name it as CustomMarkerInfoWindow. Replace the whole class with the following code:

class CustomMarkerInfoWindow: UIView {
    
    var txtLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var subtitleLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var chevronButton: UIButton = {
        let v = UIButton()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var imgView: UIImageView = {
        let v = UIImageView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = primaryColor
        self.addSubview(imgView)
        imgView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        imgView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        imgView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        imgView.widthAnchor.constraint(equalTo: imgView.heightAnchor, multiplier: 1).isActive = true
        imgView.heightAnchor.constraint(equalToConstant: 60).isActive = true
        imgView.clipsToBounds = true
        imgView.contentMode = .scaleAspectFill
        imgView.layer.cornerRadius = 5
        imgView.layer.masksToBounds = true
        imgView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
        
        self.addSubview(chevronButton)
        chevronButton.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        chevronButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8).isActive = true
        chevronButton.widthAnchor.constraint(equalToConstant: 16).isActive = true
        chevronButton.heightAnchor.constraint(equalToConstant: 16).isActive = true
        chevronButton.setImage(UIImage(named: "chevron"), for: .normal)
        chevronButton.tintColor = UIColor.white
        chevronButton.isUserInteractionEnabled = false
        
        self.addSubview(txtLabel)
        txtLabel.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 4).isActive = true
        txtLabel.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 8).isActive = true
        txtLabel.trailingAnchor.constraint(equalTo: chevronButton.leadingAnchor, constant: -8).isActive = true
        txtLabel.bottomAnchor.constraint(greaterThanOrEqualTo: centerYAnchor, constant: 2).isActive = true
        txtLabel.font = UIFont.boldSystemFont(ofSize: 16)
        txtLabel.numberOfLines = 2
        txtLabel.textColor = UIColor.white
        txtLabel.text = "dfsdfd"
        
        self.addSubview(subtitleLabel)
        subtitleLabel.topAnchor.constraint(equalTo: txtLabel.bottomAnchor, constant: 0).isActive = true
        subtitleLabel.leadingAnchor.constraint(equalTo: txtLabel.leadingAnchor).isActive = true
        subtitleLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        subtitleLabel.font = UIFont.systemFont(ofSize: 14, weight: .light)
        subtitleLabel.textColor = UIColor.white
        subtitleLabel.text = "55656556"
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        layer.masksToBounds = true
        layer.cornerRadius = 5
    }   
}

Code looks big but that's a simple auto layout.

Okay, now whenever user taps on the marker we need to change the border color to red and show info window.

First to change the selected marker color to red add the following delegate method to the extension:

func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
    guard let customMarkerView = marker.iconView as? CustomMarkerView else { return false }
    let imgName = customMarkerView.imageName
    let customMarker = CustomMarkerView(frame: CGRect(x: 0, y: 0, width: customMarkerWidth, height: customMarkerHeight), imageName: imgName, borderColor: secondaryColor, tag: customMarkerView.tag)
    marker.iconView = customMarker
    return false
}

Then to show the Marker info window add the following delegate method:

func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
     if let place = marker.userData as? SSPlace {
         marker.tracksInfoWindowChanges = true
         let infoWindow = CustomMarkerInfoWindow()
         infoWindow.tag = 5555
         let height: CGFloat = 65
         let paddingWith = height + 16 + 32
         infoWindow.frame = CGRect(x: 0, y: 0, width: getEstimatedWidthForMarker(place, padding: paddingWith) + paddingWith, height: height)
         infoWindow.imgView.image = UIImage(named: place.name!)
         infoWindow.txtLabel.text = place.name
         infoWindow.subtitleLabel.text = place.address
         return infoWindow
     }
     return nil
 }
 
 func getEstimatedWidthForMarker(_ place: SSPlace, padding: CGFloat) -> CGFloat {
     var estimatedWidth: CGFloat = 0
     let infoWindow = CustomMarkerInfoWindow()
     let maxWidth = (UIDevice.current.userInterfaceIdiom == .pad ? UIScreen.main.bounds.width * 0.7 : UIScreen.main.bounds.width * 0.8) - padding
     let titleWidth = (place.name ?? "").width(withConstrainedHeight: infoWindow.txtLabel.frame.height, font: infoWindow.txtLabel.font)
     let subtitleWidth = (place.address ?? "").width(withConstrainedHeight: infoWindow.subtitleLabel.frame.height, font: infoWindow.subtitleLabel.font)
     estimatedWidth = min(maxWidth, max(titleWidth, subtitleWidth))
     return estimatedWidth
 }
 
 extension String {
     func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
         let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
         let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
         
         return ceil(boundingBox.width)
     }
 }

The getEstimatedWidthForMarker method is to calculate the window size based on the content.

Next after closing the info window you should change marker color is default blue, for that add the following delegate method:

func mapView(_ mapView: GMSMapView, didCloseInfoWindowOf marker: GMSMarker) {
    guard let customMarkerView = marker.iconView as? CustomMarkerView else { return }
    let imgName = customMarkerView.imageName
    let customMarker = CustomMarkerView(frame: CGRect(x: 0, y: 0, width: customMarkerWidth, height: customMarkerHeight), imageName: imgName, borderColor: primaryColor, tag: customMarkerView.tag)
    marker.iconView = customMarker
}

That's it all done, run the code you will see a map with markers then tap any one of the markers you will see the info window opened with marker color changed.

Create custom info window in iOS using swift - Google maps

This tutorial looks long, but you can directly download code or check in the Github.


Read More

10 Dec 2019

Firebase Dynamic Link Not Found in swift ios

12/10/2019 04:50:00 am 0
Failed to resolve uri domain prefix: https://www.yourdomain.com.

If you are the developer of this app, ensure that your Dynamic Links domain is correctly configured and that the path component of this URL is valid.

If you are the developer of this app, ensure that your Dynamic Links domain is correctly configured and that the path component of this URL is valid.

Possible reasons for the invalid dynamic link error:

Reason 1:

First thing you need to check with apple-app-site-association as follow

paste your domain with apple-app-site-association https://www.yourdomain.com/apple-app-site-association.

Expected output should be

{"applinks":{"apps":[],"details":[{"appID":"LQABBB9F84.com.yourdomain.YourDomain","paths":["NOT /_/*","/*"]}]}}

Incase if you are getting `Dynamic Link Not Found` means check the following two things:

1. App Store ID is valid or not
2. Team ID should be same the one in provising profile

Reason 2:

Second possbile reason might be in capabilities.

Enable assocaited domains and add your domain as applinks:www.yourdomain.com.

Here make sure that you need to remove https://, otherwise deeplink url will not work as expected.

Reason 3:

If you are using any custom domains that means you are not using domains that ends with page.link, you need to add FirebaseDynamicLinksCustomDomains key in info.plist.

<key>FirebaseDynamicLinksCustomDomains</key>
<array>
    <string>https://www.yourdomain.com/test1</string>
    <string>https://www.yourdomain.com/test2</string>
</array>


Not required if you are using domains with page.link.

Reason 4:

On some iOS devices it always goes to browser, but the same link will work on other ios devices. This is because of safari caching.

Go to settings in iOS device, then tap on safari and open reader, then tap on edit select preview.page.link and delete.

Go to settings in iOS device, then tap on safari and open reader, then tap on edit select preview.page.link and delete.

That's it should work fine.

Tip: You can try pasting the url in notes app and long press on the link then tap on `open in your app'

Read More

20 Jun 2019

Add View below TabBar Controller in swift - iOS

6/20/2019 11:21:00 am 0

In this post we are going to learn how to add a subview under UITabBarController in swift 5.

Add View below TabBar Controller in swift - iOS


First download the starter project from the below link:



Open the project and run, we will  see as  below images in the simulator.



Add View below TabBar Controller in swift - iOS


In this project we have Home View controller to display list of places, Detail view controller for place detail & Account view controller for second tab.

Let’s dive into the goal.

First create new swift file subclass of UIView, name it TabBarSwitchView.swift.

In this view we are going add switch. 


Replace TabBarSwitchView class with the following code:

import UIKit

class TabBarSwitchView: UIView {
    
    let onColor = UIColor(hex: 0xF9CF2D)
    
    let offColor = UIColor.white
    
    let deselectColor = UIColor(hex: 0xBFBFBF)
    
    let bgColor = UIColor(hex: 0x404040)
    
    var travellerLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var hostLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var switchButton: UISwitch = {
        let v = UISwitch()
        v.isUserInteractionEnabled = false
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var ison: Bool = false {
        didSet {
            isTraveller = !ison
            switchButton.setOn(ison, animated: true)
            if ison {
                hostLabel.textColor = onColor
                travellerLabel.textColor = deselectColor
            }else {
                hostLabel.textColor = deselectColor
                travellerLabel.textColor = offColor
            }
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }
    
    let scale:CGFloat = 0.6
    
    func setupViews() {
        self.backgroundColor = bgColor
        self.addSubview(switchButton)
        switchButton.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
        switchButton.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true
        switchButton.onTintColor = onColor
        switchButton.tintColor = UIColor.white
        switchButton.thumbTintColor = bgColor
        switchButton.layoutIfNeeded()
        switchButton.backgroundColor = offColor
        switchButton.layer.cornerRadius = 16
        switchButton.transform = CGAffineTransform(scaleX: scale, y: scale)
        
        self.addSubview(travellerLabel)
        travellerLabel.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true
        travellerLabel.trailingAnchor.constraint(equalTo: switchButton.leadingAnchor, constant: -8).isActive = true
        travellerLabel.text = "TRAVELLER"
        travellerLabel.font = UIFont.systemFont(ofSize: 12)
        travellerLabel.textColor = UIColor.white
        
        self.addSubview(hostLabel)
        hostLabel.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0).isActive = true
        hostLabel.leadingAnchor.constraint(equalTo: switchButton.trailingAnchor, constant: 8).isActive = true
        hostLabel.text = "HOST"
        hostLabel.font = UIFont.systemFont(ofSize: 12)
        hostLabel.textColor = onColor
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
}


Next create new view controller and name it as TabBarRootVC.swift.

Replace code with following code:

import UIKit

var isTraveller = false
class TabBarRootVC: UIViewController {

    private lazy var tabBarVC: CustomTabBarVC = {
        var viewController = CustomTabBarVC()
        return viewController
    }()
    
    var bottomHeight: CGFloat {
        guard #available(iOS 11.0, *),
            let window = UIApplication.shared.keyWindow else {
                return 0
        }
        return window.safeAreaInsets.bottom
    }
    
    var switchView: TabBarSwitchView = {
        let v = TabBarSwitchView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var hideBottomBar: Bool = false {
        didSet {
            if hideBottomBar {
                heightConstraint.constant = 0
            }else {
                heightConstraint.constant = 32 + bottomHeight
            }
            UIView.animate(withDuration: 0.3) {
                self.view.layoutIfNeeded()
            }
        }
    }
    
    var heightConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
    }
    
    func setupViews() {
        self.view.backgroundColor = UIColor.white
        self.view.addSubview(switchView)
        switchView.edges([.left, .right, .bottom], to: self.view, offset: .zero)
        heightConstraint = switchView.heightAnchor.constraint(equalToConstant: 32 + bottomHeight)
        heightConstraint.isActive = true
        switchView.ison = false
        switchView.isUserInteractionEnabled = true
        switchView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(switchViewTapped(recognizer:))))
        
        addChild(tabBarVC)
        self.view.addSubview(tabBarVC.view)
        tabBarVC.view.translatesAutoresizingMaskIntoConstraints = false
        tabBarVC.view.edges([.left, .right, .top], to: self.view, offset: .zero)
        tabBarVC.view.bottomAnchor.constraint(equalTo: switchView.topAnchor, constant: 0).isActive = true
        tabBarVC.didMove(toParent: self)
        if !hideBottomBar {
            heightConstraint.constant = 32 + bottomHeight
        }else {
            heightConstraint.constant = 0
        }
        
    }
    
    @objc func switchViewTapped(recognizer: UITapGestureRecognizer) {
        switchView.ison = !switchView.ison
        isTraveller = !switchView.ison
        NotificationCenter.default.post(name: Notification.Name(rawValue: "switchChanged"), object: nil)
    }
    

}

Open utilities file and add the following extension :

extension UIViewController {
    func hideBottomSwitch(_ hide: Bool) {
        if let customTab = self.tabBarController as? CustomTabBarVC {
            customTab.hideSwitch = hide
        }
    }
}


Open CustomTabBarVC.swift file and add the following code before viewDidLoad() :

var hideSwitch: Bool = false {
    didSet {
        print("view")
        if let parentVc = self.parent as? TabBarRootVC {
            parentVc.hideBottomBar = hideSwitch
        }
    }
}

Open the HomeViewController.swift file and replace all code with the following:


import UIKit

class HomeViewController: UIViewController {
    
    var tableView: UITableView = {
        let v = UITableView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    var dataSource = [Place]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.title = "Home"
        dataSource = [Place(name: "Ocean view during daylight", hostName: "Carey", imageName: "Ocean", createdOn: "23th Mar 2019"), Place(name: "Coconut palm trees", hostName: "Stark", imageName: "Trees", createdOn: "13th Mar 2019"), Place(name: "Trees in park", hostName: "Micheal", imageName: "Park", createdOn: "28th Feb 2019"), Place(name: "Water under sunset", hostName: "Shiny", imageName: "Sunset", createdOn: "16th Feb 2019"), Place(name: "Green trees beside roadway", hostName: "Nina", imageName: "Forest", createdOn: "1st Feb 2019")]
        setupViews()
        NotificationCenter.default.addObserver(self, selector: #selector(switchChanged), name:  Notification.Name(rawValue: "switchChanged"), object: nil)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.hideBottomSwitch(false)
    }
    
    func setupViews() {
        self.navigationController?.navigationBar.isTranslucent = false
        view.addSubview(tableView)
        tableView.edges([.all], to: view.safeAreaLayoutGuide, offset: .zero)
        tableView.contentInsetAdjustmentBehavior = .never
        tableView.separatorStyle = .singleLine
        tableView.separatorInset = .zero
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CellIds.hostCellId)
        tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CellIds.travellerCellId)
    }
    
    @objc func switchChanged() {
        self.tableView.reloadData()
    }
}

extension HomeViewController: UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 80
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let vc = DetailViewController()
        vc.place = dataSource[indexPath.row]
        vc.hidesBottomBarWhenPushed = true
        self.hideBottomSwitch(true)
        self.navigationController?.pushViewController(vc, animated: true)
    }
    
}

extension HomeViewController: UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if isTraveller {
            // Traveller Cell
            let cell = tableView.dequeueReusableCell(withIdentifier: CellIds.travellerCellId, for: indexPath) as! CustomTableViewCell
            let itemAtIndex = dataSource[indexPath.row]
            cell.imgView.image = UIImage(named: itemAtIndex.imageName)
            cell.txtLabel.text = itemAtIndex.name
            cell.subtitleLabel.text = itemAtIndex.hostName
            cell.selectionStyle = .none
            return cell
        }else {
            // Host Cell
            let cell = tableView.dequeueReusableCell(withIdentifier: CellIds.hostCellId, for: indexPath) as! CustomTableViewCell
            let itemAtIndex = dataSource[indexPath.row]
            cell.imgView.image = UIImage(named: itemAtIndex.imageName)
            cell.txtLabel.text = itemAtIndex.name
            cell.subtitleLabel.text = itemAtIndex.createdOn
            cell.selectionStyle = .none
            return cell
        }
    }
    
}


Now run the project we will see output as following:

Add View below TabBar Controller in swift - iOS


Download the finished project from the following link:


Read More

27 May 2019

Enums as Constants in Swift iOS, Easily parse with JSONDecoder & JSONEncoder

5/27/2019 10:26:00 am 0
In olden languages like c, we can create enumerations with only integers. Swift allows to create enumerations in any type(int, string, Float) and easily create constants.

Enums can conform to protocols like Codable, CaseIterable.


Enums in swift, ios enums, what are enums in swift ios, Enumerations in swift 5, loop all cases in enums, json decoder and encoder for enums.Example of enums in swift, enums sample code swift

Basic Enum:

enum Beverage {
    case miller
    case kingfisher
    case corona
    case bira
    case budweiser
}

Enum with Int:

enum Numbers: Int {
    case one = 1
    case two = 2
    case three = 3
    case four = 4
    case five = 5
}

enum Numbers: Int {
    case one = 1, two, three, four1, five
}

Both are correct in swift, we can use based on our requirements.

Enum conforms to CaseIterable:

enum Juices: CaseIterable {
    case orange
    case apple
    case mango
    case pomegranate
    
    var vitamin: String {
        switch self {
        case .orange:
            return "vitamin C"
        case .apple:
            return "vitamin C"
        case .mango:
            return "vitamin K"
        case .pomegranate:
            return "vitamin C & K"
        }
    }
}

let count = Juices.allCases.count
print(count)
// 4

let org = Juices.orange
print(org.vitamin)
// vitamin C

Enum conforms to Codable: 

Codable = Decodable + Encodable

Enums can confirm to Codable protocol so that we can use JSONDecoder & JSONEncoder to parse the json object easily.

enum Status: String, Codable {
    case waitingReview = "WATING"
    case inReview = "IN"
    case rejected = "REJECTED"
    case ready = "READY"
    
    var displayString: String {
        switch self {
        case .waitingReview:
            return "Waiting for review"
        case .inReview:
            return "In review"
        case .rejected:
            return "Rejected"
        case .ready:
            return "Ready for sale"
        }
    }
}

Read More

20 Jan 2018

Multiple Component or Column PickerView Example iOS Swift 4

1/20/2018 07:48:00 am 0
Hello guys in this article we are going to create normal UIPickerView with an multi component.

We are going to collect the user's height from the multi picker view, which looks like as below image:

Multiple Component or Column PickerView Example iOS Swift 4

Let's get started, first create new Xcode project.

Open ViewController.swift file and the following required properties:

let textField = UITextField()

var pickerView: UIPickerView!

let feetList = Array(3...9)

let inchList = Array(0...11)

let numberOfComponents = 4

We created properties for textField and picker View, two arrays for height stats and numberOfComponents for picker component count.

First we add UITextField, so add the following lines of code inside viewDidLoad() method:

view.addSubview(textField)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.topAnchor.constraint(equalTo: view.topAnchor, constant: 80).isActive = true
textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
textField.heightAnchor.constraint(equalToConstant: 45).isActive = true
textField.borderStyle = .roundedRect
textField.placeholder = "What is your height?"
textField.becomeFirstResponder()

Now build and run we see an TextField..

Textfiled with picker view

Great next step, adding UIPickerView instead of regular keyboard, so add the following code to the end of viewDidLoad() method:

self.pickerView = UIPickerView(frame:CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 216))
self.pickerView.delegate = self
self.pickerView.dataSource = self
textField.inputView = self.pickerView
self.pickerView.backgroundColor = UIColor.white
textField.inputView = self.pickerView

We see some errors for not conforming to Picker View delegates. Lets add delegate methods one by one as follow:

First create extension as follow:

// MARK: - UIPickerView Methods
extension ViewController: UIPickerViewDelegate, UIPickerViewDataSource {

}

Next add following delegate & data-source methods to the above extension:

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return numberOfComponents
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    if component == 0 {
        return feetList.count
    }else if component == 2 {
        return inchList.count
    }else {
        return 1
    }
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    if component == 0 {
        return "\(feetList[row])"
    }else if component == 1 {
        return "ft"
    }else if component == 2 {
        return "\(inchList[row])"
    }else {
        return "in"
    }
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    let feetIndex = pickerView.selectedRow(inComponent: 0)
    let inchIndex = pickerView.selectedRow(inComponent: 2)
    textField.text = "\(feetList[feetIndex])'\(inchList[inchIndex])''"
}

That's it we are done with multi component pickerView.

Build and Run we see UIPickerView with multiple components as follow:

uipickerview multiple columns,uipickerview multiple components swift 4


Download sample project with example :

Read More

24 Dec 2017

How to Convert Hex(#C0C0C0) value to UIColor Swift

12/24/2017 10:28:00 pm 0
Hello guys here in this article we are going to learn about converting Hex to UIColor.

First we are creating extension to UIColor as following:

extension UIColor {
 // Code
}

Next add the following two methods inside the color extension as below:

// Create a UIColor from RGB
convenience init(red: Int, green: Int, blue: Int, a: CGFloat = 1.0) {
    self.init(
        red: CGFloat(red) / 255.0,
        green: CGFloat(green) / 255.0,
        blue: CGFloat(blue) / 255.0,
        alpha: a
    )
}

// Create a UIColor from a hex value (E.g 0xC0C0C0)
convenience init(hex: Int, a: CGFloat = 1.0) {
    self.init(
        red: (hex >> 16) & 0xFF,
        green: (hex >> 8) & 0xFF,
        blue: hex & 0xFF,
        a: a
    )
}

We are done for converting Hex to UIColor.

Lets take the following hex value:

Take Silver with hex value as #C0C0C0.

For converting the above hex value add the following line at the start of extension:

static let silver = UIColor(hex: 0xC0C0C0)

That's it now we can use silver color as follow:

let silver  = UIColor.silver


Conclusion:

If you are confused, forget above all lines of code. Simply add the following code :

extension UIColor {
    
    // Create a UIColor from RGB
    convenience init(red: Int, green: Int, blue: Int, a: CGFloat = 1.0) {
        self.init(
            red: CGFloat(red) / 255.0,
            green: CGFloat(green) / 255.0,
            blue: CGFloat(blue) / 255.0,
            alpha: a
        )
    }
    // Create a UIColor from a hex value (E.g 0x000000)
    convenience init(hex: Int, a: CGFloat = 1.0) {
        self.init(
            red: (hex >> 16) & 0xFF,
            green: (hex >> 8) & 0xFF,
            blue: hex & 0xFF,
            a: a
        )
    }
}

That's it we can use now as the follow:

let silver  = UIColor(hex: 0xC0C0C0)


Read More

27 Nov 2017

How to Record and Play Audio in iPhone using swift 4

11/27/2017 10:19:00 am 157
In this article we are going to learn about recording sound using Swift 4. Not only recording but also playing the recorded file.

Here we are using AVAudioRecorder for recording audio and AVAudioPlayer for playing the sound.

It's an easy to record using AVAudioRecorder. We will explain step by step how to record an audio.

For testing this we need a device, because simulator don't has microphone.

How to Record and Play Audio in iPhone using swift 4

Getting Started:

Firstly create a new Xcode project and name it as 'VoiceRecorder' and save.

Before getting into code we need to add Microphone usage description in Info.plist.

Open Info.plist and add 'Privacy - Microphone Usage Description' key, othersiwe app will creash.

Next open ViewController.swift file and import the following AVFoundation framework:

import AVFoundation

Next add the following properties to the view controller:

var recordButton = UIButton()
var playButton = UIButton()
var isRecording = false
var audioRecorder: AVAudioRecorder?
var player : AVAudioPlayer?

Record button is to start or stop the recording, play button is to play the recorded sound, isRecoding is an Bool to know the state, audio Recorder is to handle the actual reading and saving of data and finally player to handle the actual playing or stopping the audio.

Microphone Permission:

Next step is we need to ask the user's permission for accessing the microphone in order to stop malicious apps doing malicious things. If the user grant permission we will add the record and play button UI.

Add the following code inside viewDidLoad() method:

view.backgroundColor = UIColor.black

// Asking user permission for accessing Microphone
AVAudioSession.sharedInstance().requestRecordPermission () {
    [unowned self] allowed in
    if allowed {
        // Microphone allowed, do what you like!
        self.setUpUI()
    } else {
        // User denied microphone. Tell them off!
        
    }
}

Add the following methods for setting up the UI:

// Adding play button and record buuton as subviews
func setUpUI() {
    recordButton.translatesAutoresizingMaskIntoConstraints = false
    playButton.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(recordButton)
    view.addSubview(playButton)
    
    // Adding constraints to Record button
    recordButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    recordButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    let recordButtonHeightConstraint = recordButton.heightAnchor.constraint(equalToConstant: 50)
    recordButtonHeightConstraint.isActive = true
    recordButton.widthAnchor.constraint(equalTo: recordButton.heightAnchor, multiplier: 1.0).isActive = true
    recordButton.setImage(#imageLiteral(resourceName: "record"), for: .normal)
    recordButton.layer.cornerRadius = recordButtonHeightConstraint.constant/2
    recordButton.layer.borderColor = UIColor.white.cgColor
    recordButton.layer.borderWidth = 5.0
    recordButton.imageEdgeInsets = UIEdgeInsetsMake(-20, -20, -20, -20)
    recordButton.addTarget(self, action: #selector(record(sender:)), for: .touchUpInside)
    
    // Adding constraints to Play button
    playButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
    playButton.widthAnchor.constraint(equalTo: playButton.heightAnchor, multiplier: 1.0).isActive = true
    playButton.trailingAnchor.constraint(equalTo: recordButton.leadingAnchor, constant: -16).isActive = true
    playButton.centerYAnchor.constraint(equalTo: recordButton.centerYAnchor).isActive = true
    playButton.setImage(#imageLiteral(resourceName: "play"), for: .normal)
    playButton.addTarget(self, action: #selector(play(sender:)), for: .touchUpInside)
}

@objc func record(sender: UIButton) {

}

@objc func play(sender: UIButton) {
    
}

Here we added button using auto layout constraints programmatically.

Build and Run, next allow the Microphone for recording. Then the screen looks like below:

Play and stop button for recording swift 4

Start recording:

All buttons setting up done, next step is to start recording.

Add the following method to record an audio:

func startRecording() {
    //1. create the session
    let session = AVAudioSession.sharedInstance()
    
    do {
        // 2. configure the session for recording and playback
        try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker)
        try session.setActive(true)
        // 3. set up a high-quality recording session
        let settings = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 44100,
            AVNumberOfChannelsKey: 2,
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
        ]
        // 4. create the audio recording, and assign ourselves as the delegate
        audioRecorder = try AVAudioRecorder(url: getAudioFileUrl(), settings: settings)
        audioRecorder?.delegate = self
        audioRecorder?.record()
        
        //5. Changing record icon to stop icon
        isRecording = true
        recordButton.setImage(#imageLiteral(resourceName: "stop"), for: .normal)
        recordButton.imageEdgeInsets = UIEdgeInsetsMake(5, 5, 5, 5)
        playButton.isEnabled = false
    }
    catch let error {
        // failed to record!
    }
}

Here we created AVAudioSession and creating audio recording. Add the following method for getting the path to save or retrieve the audio.

// Path for saving/retreiving the audio file
func getAudioFileUrl() -> URL{
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let docsDirect = paths[0]
    let audioUrl = docsDirect.appendingPathComponent("recording.m4a")
    return audioUrl
}

Next step is to conform to AVAudioRecorderDelegate protocol as follow:

class ViewController: UIViewController, AVAudioRecorderDelegate {

Next add the following code inside record() method:

Stop Recording:

Add the following method to stop recording an audio.

// Stop recording
func finishRecording() {
    audioRecorder?.stop()
    isRecording = false
    recordButton.imageEdgeInsets = UIEdgeInsetsMake(-20, -20, -20, -20)
    recordButton.setImage(#imageLiteral(resourceName: "record"), for: .normal)
}

Just needs to call either startRecording() or finishRecording() depending on the isRecording state.

Next add the following code inside record() method:

if isRecording {
    finishRecording()
}else {
    startRecording()
}

Before you're done, there's one more thing to be aware of: iOS might stop your recording for some reason out of your control, such as if a phone call comes in. We use the delegate of the audio recorder, so if this situation crops up you'll be sent a audioRecorderDidFinishRecording() message that you can pass on to finishRecording() like this:

func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
    if flag {
        finishRecording()
    }else {
        // Recording interrupted by other reasons like call coming, reached time limit.
    }
    playButton.isEnabled = true
}

That's it recording an audio successfully completed.

Play Audio:

For playing sound we are using AVAudioPlayer, so add the following method:

func playSound(){
    let url = getAudioFileUrl()
    
    do {
        // AVAudioPlayer setting up with the saved file URL
        let sound = try AVAudioPlayer(contentsOf: url)
        self.player = sound
        
        // Here conforming to AVAudioPlayerDelegate
        sound.delegate = self
        sound.prepareToPlay()
        sound.play()
        recordButton.isEnabled = false
    } catch {
        print("error loading file")
        // couldn't load file :(
    }
}

Conform to the AVAudioPlayerDelegate protocol as follow:

class ViewController: UIViewController, AVAudioRecorderDelegate, AVAudioPlayerDelegate {

Next call the following method inside play() method as follow:

@objc func play(sender: UIButton) {
    playSound()
}

Add the AVAudioPlayerDelegate delegate method audioPlayerDidFinishPlaying() as follow to know whether audio finished playing or interrupted by an reason.

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    if flag {
        
    }else {
        // Playing interrupted by other reasons like call coming, the sound has not finished playing.
    }
    recordButton.isEnabled = true
}

Great we are done, it's time to run and test.

Download sample project with example :

Read More

20 Nov 2017

How to convert Range to NSRange and Viceversa

11/20/2017 10:25:00 am 2
NSRange contains two properties.

1. location
2. length

How to convert Range to NSRange and Viceversa

For example:

Get the range of word "find" from the following string.

let originalString = "Hello let's find range"

"find" located at position 12, and is length of 4. So range should be as follow:

let range = NSMakeRange(12, 4)

Range:

For getting range we have built in method as follow:

let originalString = "Hello let's find range"
let range = originalString.range(of: "find")

Convert Range to NSRange:

Add the following string extension for converting Range to NSRange:

extension String {
    func nsRange(from range: Range) -> NSRange {
        let startPos = self.distance(from: self.startIndex, to: range.lowerBound)
        let endPos = self.distance(from: self.startIndex, to: range.upperBound)
        return NSMakeRange(startPos, endPos - startPos)
    }
}

Use as follow:

let nsRange = originalString.nsRange(from: range!)

Convert NSRange to Range:

Add the following string extension for converting NSRange to Range:

extension String { 
    func range(from nsRange: NSRange) -> Range? {
        guard
            let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
            let to16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location + nsRange.length, limitedBy: utf16.endIndex),
            let from = from16.samePosition(in: self),
            let to = to16.samePosition(in: self)
            else { return nil }
        return from ..< to
    }
}

Use as follow:

let newRange = originalString.range(from: nsRange)

Read More

18 Nov 2017

UIRotationGestureRecognizer - Rotate image with Two Fingers in swift

11/18/2017 09:37:00 am 1
In this tutorial we will learn how to rotate an imageView using UIRotationGestureRecognizer.

A rotation gesture is a continuous gesture that occurs when the first two fingers that touch the screen rotate around each other

The iOS UIRotationGestureRecognizer class has a built-in way to detect rotation gesture on any view.

UIRotationGestureRecognizer - Rotate image with Two Fingers in swift

Other Gestures in iOS:

Getting Started:

Firstly create new Xcode project and save it with 'RotationGesture'.

Next open the ViewController.swift file and add the imageView as follow.

Adding ImageView:

First create imageView property as follow:

let imageView = UIImageView()

Next add imageView as sub view and give the auto layout constraints. Add the following code in viewDidLoad() method:

imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = UIImage(named: "cat")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
view.addSubview(imageView)
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
imageView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.6).isActive = true
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1).isActive = true

Adding Rotation Gesture:

First create an instance to UIRotationGestureRecognizer() as follow:

var rotationGesture = UIRotationGestureRecognizer()

Next add rotationGesture to the imageView. Add the following code to the end of viewDidLoad() method:

rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(self.rotationGestureHandler))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(rotationGesture)

The isUserInteractionEnabled property of the view is set to true. Image views and labels set this property to false by default.

Finally add the action for the rotate gesture, add the following method:

@objc func rotationGestureHandler(recognizer:UIRotationGestureRecognizer){
    if let view = recognizer.view {
        view.transform = view.transform.rotated(by: recognizer.rotation)
        recognizer.rotation = 0
    }
}

Run the project, we will see an image with an rotate gesture as follow:

UIRotationGestureRecognizer - Rotate image with Two Fingers in swift-gif
Download sample project with example :

Read More

16 Nov 2017

UILongPressGestureRecognizer - Image zoom in and out example on Long Press Gesture in swift

11/16/2017 08:54:00 am 0
In this tutorial we will learn how to zoom in and out an imageView using UILongPressGestureRecognizer.

The iOS UILongPressGestureRecognizer class has a built-in way to detect long press gesture on any view.

UILongPressGestureRecognizer - Image zoom in and out example on Long Press Gesture in swift gif

Other Gestures in iOS:


Getting Started:

Firstly create new Xcode project and save it with 'LongPressGesture'.

Next open the ViewController.swift file and add the imageView as follow.

Adding ImageView:

First create imageView property as follow:

let imageView = UIImageView()

Next add imageView as sub view and give the auto layout constraints. Add the following code in viewDidLoad() method:

imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = UIImage(named: "cat")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
view.addSubview(imageView)
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
imageView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4).isActive = true
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 1).isActive = true

Adding Long Press Gesture:

First create an instance to UILongPressGestureRecognizer() as follow:

var longPressGesture = UILongPressGestureRecognizer()

Next add longPressGesture to the imageView. Add the following code to the end of viewDidLoad() method:

longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGestureHandler))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(longPressGesture)

The isUserInteractionEnabled property of the view is set to true. Image views and labels set this property to false by default.

Finally add the action for the long press gesture, add the following method:

@objc func longPressGestureHandler(recognizer:UIPinchGestureRecognizer){
    switch recognizer.state {
    case .began:
        UIView.animate(withDuration: 0.05,
                       animations: {
                        self.imageView.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
        },
                       completion: nil)
    case .ended:
        UIView.animate(withDuration: 0.05) {
            self.imageView.transform = CGAffineTransform.identity
        }
    default: break
    }
}

Run the project, we will see an image with an long press gesture as follow:

Tap on image and hold for 1 sec we will see image zoom in as follow:

UILongPressGestureRecognizer - Image zoom in and out example on Long Press Gesture in swift

Download sample project with example :

Read More

Post Top Ad