Search code examples
iosswiftuiscrollviewscrollviewframe

Recenter the scrollview content Swift


I'm trying to recenter the scrollview view and move the frame, when the user current location goes to the out of the screen frame. Currently I have a PDF and I'm showing the user's current location, I am calculating the frame and scrollview zoomScale to showing the current location on PDF View. I achieve this functionality already. It's working perfectly and I am already drawing the path with the same logic when the user moves, but I'm stuck at the last point when the user moves and goes out of the screen means hide from the mobile screen then we need to recenter the current location.

First Code:-

Code:-

override func viewDidLoad() {
    super.viewDidLoad()
    self.initPdfView()
    self.initCurrentLocation()
}

func initPdfView() {
    do {
        let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        if let path = paths.first {
            let fileURL = URL(fileURLWithPath: path).appendingPathComponent("MapBox")
            let document = try PDFDocument.init(at: fileURL)
            pdfController?.page = try document.page(0)
            pdfController?.scrollDelegates = self
            pdfController?.scrollView.layoutSubviews()
        }
    } catch {
        print(error.localizedDescription)
    }
}
   
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let visibleRect = CGRect.init(x: sender.contentOffset.x, y: sender.contentOffset.y, width: sender.contentSize.width*sender.zoomScale, height: sender.contentSize.height*sender.zoomScale)
    self.visibleScrollViewRect = visibleRect
    self.zooomLevel = sender.zoomScale
}

func initCurrentLocation() {
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
    
    if CLLocationManager.locationServicesEnabled() {
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startUpdatingLocation()
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
    self.currentLocation = locValue
}

ScreenShot:-

In first Screenshot, I'm showing the user's current location.

First Screenshot

In second Screenshot, I'm drawing the path with the help of user's current location.

Second Screenshot

In third Screenshot, When user moves and goes out of the screen means hide from the mobile screen.

Third Screenshot

Second Code:-

func initMapDataUserView() {
    guard let mapInfoJson = decodeMapInfo(with: "MapBoxUrl") else {
        return
    }
    
let position = CGPoint.init(x: mapInfoJson.rasterXYsize.first!, y: mapInfoJson.rasterXYsize.last!)
let pointerVal: UnsafePointer<Int8>? = NSString(string: mapInfoJson.projection).utf8String
let decoder = GeoDecode()
    decoder.fetchPdfCoordinateBounds(with: position, projection: pointerVal, initialTransform: mapInfoJson.geotransform) { coordinate, error in
        if let error = error {
            debugPrint(error)
        } else {
            guard let coordinate = coordinate else {
                return
            }
            self.coordinatesUserCurrentLocation = coordinate
            self.initCurrentLocation()
        }
      }
   }

  func initPdfView() {
    do {
        let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        if let path = paths.first {
            let fileURL = URL(fileURLWithPath: path).appendingPathComponent("MapBoxUrl")
            let document = try PDFDocument.init(at: fileURL)
            viewPDFController?.page = try document.page(0)
            viewPDFController?.scrollDelegates = self
            viewPDFController?.scrollView.layoutSubviews()
        }
    } catch {
        print(error.localizedDescription)
    }
}


func decodeMapInfo(with value: String) -> MapInfoJson? {
    do {
        guard let valueData = value.data(using: .utf8) else {
            return nil
        }
        let decodedResult = try JSONDecoder().decode(MapInfoJson.self, from: valueData)
        return decodedResult
    } catch {
        print("error: ", error)
    }
    return nil
}

extension MapPreviewViewController: scrollViewActions {

func scrollViewScroll(_ sender: UIScrollView) {
    let visibleRect = CGRect.init(x: sender.contentOffset.x, y: sender.contentOffset.y, width: sender.contentSize.width*sender.zoomScale, height: sender.contentSize.height*sender.zoomScale)
    self.visibleScrollViewRectUserScreen = visibleRect
    self.zooomLevelScrollView = sender.zoomScale
    if coordinatesUserCurrentLocation != nil {
        updateMarkerVisiblityOnPdfView()
      }
   }
}


extension MapPreviewViewController: CLLocationManagerDelegate {

func initCurrentLocation() {
    locationManagerUserTest.delegate = self
    locationManagerUserTest.desiredAccuracy = kCLLocationAccuracyBest
    locationManagerUserTest.requestAlwaysAuthorization()
    
    if CLLocationManager.locationServicesEnabled() {
        locationManagerUserTest.desiredAccuracy = kCLLocationAccuracyBest
        locationManagerUserTest.startUpdatingLocation()
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
    self.currentLocationUser = locValue
    updateMarkerVisiblityOnPdfView()
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    
}

func updateMarkerVisiblityOnPdfView() {
    guard let locValue: CLLocationCoordinate2D = self.currentLocationUser else { return }
    guard let coordinates = coordinatesUserCurrentLocation else { return }
    
    let yFactor = (locValue.longitude - coordinates.minY) / (coordinates.maxY - coordinates.minY)
    let xFactor = (coordinates.maxX - locValue.latitude) / (coordinates.maxX - coordinates.minX)
    
    var positionX: Double = 0.0
    var positionY: Double = 0.0
    
    positionX = (yFactor*Double(visibleScrollViewRectUserScreen!.size.width))/Double(self.zooomLevelScrollView!)
    positionY = (xFactor*Double(visibleScrollViewRectUserScreen!.size.height))/Double(self.zooomLevelScrollView!)
    
    if visibleScrollViewRectUserScreen!.size.width < 1.0 {
        positionX = (yFactor*Double(18))*Double(self.zooomLevelScrollView!)
        positionY = (xFactor*Double(18))*Double(self.zooomLevelScrollView!)
    }
    
    var indexOfExistingImageView: Int?
    
    for index in 0..<viewPDFController!.scrollView.subviews.count {
        if let imageview = viewPDFController!.scrollView.subviews[index] as? UIImageView {
            if imageview.image == currentmarkerImagView.image {
                indexOfExistingImageView = index
            }
        }
    }
    
    self.currentmarkerImagView.center = .init(x: positionX, y: positionY)
    self.viewPDFController!.scrollView.addSubview(currentmarkerImagView)
    self.viewPDFController!.scrollView.bringSubviewToFront(currentmarkerImagView)
    
   }
 }


public protocol scrollViewActions {
func scrollViewScroll(_ sender: UIScrollView)
}

public class PdfViewViewController: UIViewController {
public var scrollView: UIScrollView!
public var overlayView: UIView!
public var contentView: UIView!
public var scrollDelegates: scrollViewActions?

public override func viewDidLoad() {
    super.viewDidLoad()
     
    scrollView.delegate = self
    scrollView.contentInsetAdjustmentBehavior = .never
     }
  }

  extension PdfViewViewController: UIScrollViewDelegate {
 public func scrollViewDidScroll(_ scrollView: UIScrollView) {
    scrollDelegates?.scrollViewScroll(scrollView)
}

public func scrollViewDidZoom(_ scrollView: UIScrollView) {
    scrollDelegates?.scrollViewScroll(scrollView)
}

public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    scrollDelegates?.scrollViewScroll(scrollView)
}

public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
}

public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
}

public func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
    }
}

Updated ScreenShot:

In first Screenshot, I'm showing the user's current location.

First Screenshot

In second Screenshot, When user moves and goes out of the screen means hide from the mobile screen.

Second Screenshot

Question: Can someone please explain to me how to recenter the current location or move the scrollview frame when user moves and goes out of the screen.

Any help would be greatly appreciated.

Thanks in advance.


Solution

  • I found solution to check and set pdf scrollview Center.

    Code:-

     func getCurrentLocMakerOutSideFrameOrNot() {
        var visibleRect = CGRect.init(x: 0, y: 0, width: 0, height: 0)
        visibleRect.origin = scrollView.contentOffset
        visibleRect.size = scrollView.bounds.size
         
        if !visibleRect.intersects(currentmarkerImagView.frame) {
            print("Outer View")
            guard let locValue: CLLocationCoordinate2D = self.currentLocation else { return }
            guard let coordinates = coordinates else { return }
            
            let yFactor = (locValue.longitude - coordinates.minY) / (coordinates.maxY - coordinates.minY)
            let xFactor = (coordinates.maxX - locValue.latitude) / (coordinates.maxX - coordinates.minX)
            
            var positionX: Double = 0.0
            var positionY: Double = 0.0
            
            positionX = (yFactor*Double(visibleScrollViewRectView!.size.width))/Double(self.zooomLevelView!)
            positionY = (xFactor*Double(visibleScrollViewRectView!.size.height))/Double(self.zooomLevelView!)
            
            if visibleScrollViewRectView!.size.width < 1.0 {
                positionX = (yFactor*Double(18))*Double(self.zooomLevelView!)
                positionY = (xFactor*Double(18))*Double(self.zooomLevelView!)
            }
    
            let centerPoint = CGPoint(x: positionX-190, y: positionY-295)
    
            UIView.animate(withDuration: 2.5, animations: {
                  scrollView.setContentOffset(centerPoint, animated: false)
                  scrollView.setZoomScale(self.pdfController!.scrollView.zoomScale/2, animated: false)
             })
        }
    }