Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing MapViewPort to MapViewProxy #65

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

hactar
Copy link
Collaborator

@hactar hactar commented Dec 11, 2024

Issue/Motivation

MLNMapView offers many properties and functions that are useful to developers, things like contentInset or convert functions can be used to create more complex camera interactions, like checking if a Feature is already visible on the map (and not covered by a bottom sheet or similar), and if it is, not moving the camera.

At the same time we don't want to expose MLNMapView to developers, as this would allow developers to modify MLNMapView in a way that clashes with swiftui-dsl.

This PR changes the existing MapViewPort to instead be MapViewProxy: a read only proxy to functions and properties of MLNMapView. This way, developers can store a reference to the MapViewProxy struct, and get access to properties and functions of the MLNMapView. The MLNMapView is not directly exposed, and only functions are exposed that do not alter state. Properties are only expose their getter.

The proxy pattern is already used by features such as GeometryReader or ScrollViewReader. Newer functions of swift appear not to use the reader pattern, but prefer a onChange pattern, for example https://www.hackingwithswift.com/quick-start/swiftui/how-to-detect-when-the-size-or-position-of-a-view-changes - so SwiftUI users should feel right at home.

This allows developers to write a function like this:

    func isCoordinateVisible(coordinate: CLLocationCoordinate2D, mapViewProxy: MapViewProxy) -> Bool {
        /// visibleCoordinateBounds ignores the map view contentInset
        let bounds = mapViewProxy.visibleCoordinateBounds
        
        // test if the coordinate is within the visible map, ignoring insets
        if MLNCoordinateInCoordinateBounds(coordinate, bounds) == false {
            return false
        }
        
        // test if the coordinate is covered by the contentInset
        // Get the content inset
        
        // Convert the CLLocationCoordinate2D to a CGPoint
        let point = mapViewProxy.convert(coordinate, toPointTo: nil)
        
        // Calculate the adjusted frame for the visible portion of the map view
        let adjustedFrame = CGRect(
            x: mapViewProxy.contentInset.left,
            y: mapViewProxy.contentInset.top,
            width: mapViewProxy.mapViewSize.width - mapViewProxy.contentInset.left - mapViewProxy.contentInset.right,
            height: mapViewProxy.mapViewSize.height - mapViewProxy.contentInset.top - mapViewProxy.contentInset.bottom
        )
        
        // Check if the point is inside the adjusted frame
        return adjustedFrame.contains(point)
    }

Additional Information

I have only exposed the properties that I need for my specific use case, but if we agree with this implementation, future properties and functions that are to be exposed could be added here.

I have renamed the properties that MapViewProxy already had to their MLNMapView name: my thinking here is that this way, people can directly use the MLNMapView documentation on the usage of these properties,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant