Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Animating map view contraints is jerky; implicit animation via Core Animation properties not supported #4352

Open
friedbunny opened this issue Mar 16, 2016 · 19 comments
Labels
bug gl-ios iOS Mapbox Maps SDK for iOS MapKit parity For feature parity with MapKit on iOS or macOS
Milestone

Comments

@friedbunny
Copy link
Contributor

The proper way to animate MGLMapView is to modify its auto layout constraints (and not the frame), but this doesn’t behave correctly:

  • White gaps at top and bottom jump as the map frame instantly shrinks to fit, rather than animate to the new, smaller constraint. The logo and attribution subviews do animate correctly, which indicates this is an issue with the GLKView that provides the map itself.
  • User location annotation does not move, it just sits around waiting to be in the correct spot again.

animating-constraint-jumping

Preview of the test project:

screen shot 2016-03-16 at 3 10 26 pm

import UIKit
import Mapbox

class ViewController: UIViewController {

    @IBOutlet weak var mapView: MGLMapView!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        mapView.showsUserLocation = true
    }

    @IBAction func animate(sender: AnyObject) {
        UIView.animateWithDuration(1.5, delay: 0, options: .CurveEaseOut, animations: {
            self.mapView.userInteractionEnabled = false

            self.heightConstraint.constant = self.heightConstraint.constant > 200 ? 200 : self.view.frame.height/2

            self.view.layoutIfNeeded()
        }, completion: { finished in
            self.mapView.userInteractionEnabled = true
        })
    }

}

/cc @1ec5 @boundsj

@friedbunny friedbunny added bug iOS Mapbox Maps SDK for iOS labels Mar 16, 2016
@harri121
Copy link

+1

@harri121
Copy link

Is there a workaround?

@1ec5
Copy link
Contributor

1ec5 commented Apr 17, 2016

I’m not sure about a workaround, but I suspect the problem may be that -layoutSubviews only gets called at the beginning of the animation, so mbgl::Map::update() gets called only once with the final size. Meanwhile, the user dot appears to stay stationary because it’s actually animating in the opposite direction to compensate. (If the map view is flush with the bottom of the view controller, showing and hiding the bottom bar will cause the user dot to visibly slide into place.)

@1ec5
Copy link
Contributor

1ec5 commented Apr 17, 2016

The fix is probably to move the call to mbgl::Map::update() from -layoutSubviews to the -setFrame: or -setBounds: override and also have MBGLView::getSize() return GLKView’s presentation layer’s size instead of MGLMapView’s explicit size.

@1ec5 1ec5 added this to the ios-v3.3.0 milestone Apr 17, 2016
@harri121
Copy link

Ok, do you know when this will be fixed?

@friedbunny friedbunny modified the milestones: ios-v3.4.0, ios-v3.3.0 Jun 17, 2016
@boundsj boundsj modified the milestones: ios-v3.4.0, ios-future Jul 11, 2016
@afinlayson
Copy link

Looking for this as well.
Thanks

@lilykaiser
Copy link

Closing due to ticket age. If this is still a problem, please re-open

@katiesmillie
Copy link

@friedbunny I'm also having this issue and would appreciate an update. Are there any workarounds?

@1ec5
Copy link
Contributor

1ec5 commented Sep 24, 2018

As a possible starting point, we should check whether -[GLKView drawableHeight] is even animatable:

return { static_cast<uint32_t>(self.glView.drawableWidth),
static_cast<uint32_t>(self.glView.drawableHeight) };

@stale
Copy link

stale bot commented Mar 23, 2019

This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions.

@stale stale bot closed this as completed Mar 23, 2019
@katiesmillie
Copy link

This is still an issue that I've been following and hoping for a resolution. I hope you'll consider re-opening it.

The best workaround that I've come up with is to leave the size of the mapview unchanged, and change the content insets of the map (which adjusts the coordinates bounds and center of the map). The map animation happens after the second view has been finished animating so you lose the effect you see above where they both animate together. This significantly degrades the experience as it has become a very common mobile UI pattern with all the major map apps.

@julianrex julianrex removed the archived Archived because of inactivity label Mar 25, 2019
@julianrex
Copy link
Contributor

This is still open @katiesmillie!

Your workaround of changing the content insets may actually be part of the solution that we're looking at (or similar) - since adjusting the frame buffers during an animation gives poor performance.

@julianrex julianrex reopened this Mar 25, 2019
@julianrex julianrex removed their assignment Apr 8, 2019
@pappalar
Copy link

+1 for this issue

@pappalar
Copy link

The same issue is also happening when the iOS tab bar or Navigation Bar are showing animated. as the container of the map will change constrains animated.

I also noticed that changing the content inset (animated if I remember correctly) also does not redraw the current location annotation position (as originally reported)

@1ec5
Copy link
Contributor

1ec5 commented May 13, 2019

The root cause of the original report is that MGLMapView.camera, centerCoordinate, etc. are not implicitly animatable. (Notice how the constraint is being modified inside an implicit animation block.) Supporting implicit animation for the camera properties would be one side effect of reimplementing camera animation atop Core Animation: #9808.

@1ec5
Copy link
Contributor

1ec5 commented May 29, 2019

Replacing GLKView with a built-in Core Animation layer (#14785) would make the effect somewhat less jarring, as it is on macOS. The layer’s frame would animate correctly, though the content could potentially stretch or compress to fit that frame during the animation. Supporting implicit animation is the correct fix no matter what.

@pappalar
Copy link

@1ec5 Would it be possible and is the idea to support animation for the camera and centerCoordinate etc?

We noticed that changing the inset/frame of the map while zooming the camera will:

trigger uiView SafeAreaInsetChanged

mapView.adjustContentInset

which calls MGLMapView.cancelTransitions that also destroy the camera anmations

@1ec5
Copy link
Contributor

1ec5 commented Aug 1, 2019

Would it be possible and is the idea to support animation for the camera and centerCoordinate etc?

Yes, I think implicit animation of these properties is essentially what this issue tracks. There is a separate effort to overhaul the camera APIs on both Android and iOS/macOS, which is sort of tracked in #9808, but I think we have to solve this issue regardless, especially considering the prominence of implicit animation in SwiftUI.

@1ec5 1ec5 added the MapKit parity For feature parity with MapKit on iOS or macOS label Aug 1, 2019
@1ec5 1ec5 changed the title Animating map view contraints is jerky and does not update properly Animating map view contraints is jerky; implicit animation via Core Animation properties not supported Sep 10, 2019
@robert-frankin
Copy link

robert-frankin commented Apr 17, 2020

Hi, I am getting same issue in iOS. Is there any solution to fix it? Please advise. @1ec5

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug gl-ios iOS Mapbox Maps SDK for iOS MapKit parity For feature parity with MapKit on iOS or macOS
Projects
None yet
Development

No branches or pull requests