New iOS Dev
New iOS Dev

Reputation: 2057

how to use location for Eureka pod for iOS form?

I have added various filed successfully using Eureka form builder for iOS but getting an error while adding locationrow r

I imported following framework still getting the issue import UIKit import CoreLocation import MapKit import Eureka

is there any other way to use locationrow in eureka?

Upvotes: 0

Views: 432

Answers (3)

Joliet123
Joliet123

Reputation: 1

I created a separate folder/file for the location code

import Foundation
import UIKit
import MapKit
import Eureka


//MARK: LocationRow
public final class LocationRow: OptionsRow<PushSelectorCell<CLLocation>>, PresenterRowType, RowType {

public typealias PresenterRow = MapViewController

/// Defines how the view controller will be presented, pushed, etc.
public var presentationMode: PresentationMode<PresenterRow>?

/// Will be called before the presentation occurs.
public var onPresentCallback: ((FormViewController, PresenterRow) -> Void)?

public required init(tag: String?) {
    super.init(tag: tag)
    presentationMode = .show(controllerProvider: ControllerProvider.callback { return MapViewController(){ _ in } }, onDismiss: { vc in _ = vc.navigationController?.popViewController(animated: true) })

    displayValueFor = {
        guard let location = $0 else { return "" }
        let fmt = NumberFormatter()
        fmt.maximumFractionDigits = 4
        fmt.minimumFractionDigits = 4
        let latitude = fmt.string(from: NSNumber(value: location.coordinate.latitude))!
        let longitude = fmt.string(from: NSNumber(value: location.coordinate.longitude))!
        return  "\(latitude), \(longitude)"
    }
}

/**
 Extends `didSelect` method
 */
public override func customDidSelect() {
    super.customDidSelect()
    guard let presentationMode = presentationMode, !isDisabled else { return }
    if let controller = presentationMode.makeController() {
        controller.row = self
        controller.title = selectorTitle ?? controller.title
        onPresentCallback?(cell.formViewController()!, controller)
        presentationMode.present(controller, row: self, presentingController: self.cell.formViewController()!)
    } else {
        presentationMode.present(nil, row: self, presentingController: self.cell.formViewController()!)
    }
}

/**
 Prepares the pushed row setting its title and completion callback.
 */
public override func prepare(for segue: UIStoryboardSegue) {
    super.prepare(for: segue)
    guard let rowVC = segue.destination as? PresenterRow else { return }
    rowVC.title = selectorTitle ?? rowVC.title
    rowVC.onDismissCallback = presentationMode?.onDismissCallback ?? rowVC.onDismissCallback
    onPresentCallback?(cell.formViewController()!, rowVC)
    rowVC.row = self
}
}

public class MapViewController : UIViewController, TypedRowControllerType, MKMapViewDelegate {

public var row: RowOf<CLLocation>!
public var onDismissCallback: ((UIViewController) -> ())?

lazy var mapView : MKMapView = { [unowned self] in
    let v = MKMapView(frame: self.view.bounds)
    v.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    return v
    }()

lazy var pinView: UIImageView = { [unowned self] in
    let v = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
    v.image = UIImage(named: "map_pin", in: Bundle(for: MapViewController.self), compatibleWith: nil)
    v.image = v.image?.withRenderingMode(.alwaysTemplate)
    v.tintColor = self.view.tintColor
    v.backgroundColor = .clear
    v.clipsToBounds = true
    v.contentMode = .scaleAspectFit
    v.isUserInteractionEnabled = false
    return v
    }()

let width: CGFloat = 10.0
let height: CGFloat = 5.0

lazy var ellipse: UIBezierPath = { [unowned self] in
    let ellipse = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: self.width, height: self.height))
    return ellipse
    }()


lazy var ellipsisLayer: CAShapeLayer = { [unowned self] in
    let layer = CAShapeLayer()
    layer.bounds = CGRect(x: 0, y: 0, width: self.width, height: self.height)
    layer.path = self.ellipse.cgPath
    layer.fillColor = UIColor.gray.cgColor
    layer.fillRule = .nonZero
    layer.lineCap = .butt
    layer.lineDashPattern = nil
    layer.lineDashPhase = 0.0
    layer.lineJoin = .miter
    layer.lineWidth = 1.0
    layer.miterLimit = 10.0
    layer.strokeColor = UIColor.gray.cgColor
    return layer
    }()


required public init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nil, bundle: nil)
}

convenience public init(_ callback: ((UIViewController) -> ())?){
    self.init(nibName: nil, bundle: nil)
    onDismissCallback = callback
}

public override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(mapView)

    mapView.delegate = self
    mapView.addSubview(pinView)
    mapView.layer.insertSublayer(ellipsisLayer, below: pinView.layer)

    let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(MapViewController.tappedDone(_:)))
    button.title = "Done"
    navigationItem.rightBarButtonItem = button

    if let value = row.value {
        let region = MKCoordinateRegion(center: value.coordinate, latitudinalMeters: 400, longitudinalMeters: 400)
        mapView.setRegion(region, animated: true)
    }
    else{
        mapView.showsUserLocation = true
    }
    updateTitle()

}

public override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let center = mapView.convert(mapView.centerCoordinate, toPointTo: pinView)
    pinView.center = CGPoint(x: center.x, y: center.y - (pinView.bounds.height/2))
    ellipsisLayer.position = center
}


@objc func tappedDone(_ sender: UIBarButtonItem){
    let target = mapView.convert(ellipsisLayer.position, toCoordinateFrom: mapView)
    
    row.value = CLLocation(latitude: target.latitude, longitude: target.longitude)
    onDismissCallback?(self)
}

func updateTitle(){
    let fmt = NumberFormatter()
    fmt.maximumFractionDigits = 4
    fmt.minimumFractionDigits = 4
    let latitude = fmt.string(from: NSNumber(value: mapView.centerCoordinate.latitude))!
    let longitude = fmt.string(from: NSNumber(value: mapView.centerCoordinate.longitude))!
    title = "\(latitude), \(longitude)"
    
}

public func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
    ellipsisLayer.transform = CATransform3DMakeScale(0.5, 0.5, 1)
    UIView.animate(withDuration: 0.2, animations: { [weak self] in
        self?.pinView.center = CGPoint(x: self!.pinView.center.x, y: self!.pinView.center.y - 10)
        })
}

public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    ellipsisLayer.transform = CATransform3DIdentity
    UIView.animate(withDuration: 0.2, animations: { [weak self] in
        self?.pinView.center = CGPoint(x: self!.pinView.center.x, y: self!.pinView.center.y + 10)
        })
    updateTitle()
}
}

In my form, I just added a new row like this:

<<< LocationRow("Location"){
        $0.title = $0.tag
        $0.value = CLLocation(latitude: -34.9124, longitude: -56.1594)
    }

This is also a good resource to use. https://fluttergeek.com/blog/eureka-locationrow/

Upvotes: 0

bohdans
bohdans

Reputation: 49

LocationRow (Included as custom row in the example project)

These words were taken from https://github.com/xmartlabs/Eureka

So far Location Row can't be included into Eureka framework cause it's required MapKit or something similar, that's why eureka community created separated class/object.

Upvotes: 0

Dinesh Tanwar
Dinesh Tanwar

Reputation: 41

you will have to first add LocationRow in your pod file and then update your pod file so that cocoapod downloads LocationRow. build the project once to refresh the project with the new files.

and then in the above class import LocationRow

Upvotes: 0

Related Questions