How to show MapKit compass? - ios

Currently the compass only get's shown if a User applies a rotate-gesture. Otherwise the compass is hidden.
But it would be nice if my two wishes below were fulfilled!
Is it possible to display the compass always?
How to show / hide the compass-view using Swift?

You can do this quite easily in iOS 11 by using the new MKCompassButton class.
You need to create an instance of MKCompassButton and add it to your map view. You can then set its compassVisibility property to one of:
.visible - always visible
.never - never visible
.adaptive - the compasss is only visible if the map is rotated away from a North/up orientation.
If you keep a reference to the compass in a property you can change its visibility as you need:
mapview.showsCompass = false // Hide built-in compass
compassButton = MKCompassButton(mapView: mapview) // Make a new compass
compassButton.compassVisibility = .visible // Make it visible
mapview.addSubview(compassButton) // Add it to the view
// Position it as required
compassButton.translatesAutoresizingMaskIntoConstraints = false
compassButton.trailingAnchor.constraint(equalTo: mapview.trailingAnchor, constant: -12).isActive = true
compassButton.topAnchor.constraint(equalTo: mapview.topAnchor, constant: 12).isActive = true
Unfortunately, for prior versions of iOS there is no simple solution. I have seen suggestions that involve looking through the map view's subviews to try and find the compass view but there seems to be mixed results.

Related

AutoLayout Constraints Across All Devices Mathematically

I am new to IOS Development, please go easy.
I am attempting to create a universal identically positioned UIView in the main ViewController of any IOS Device (The view will change dynamically and match across all IOS devices (relative to the size of the screen), and not ruin the positioning of the view). Basically, is it possible to mathematically alter the "equalToConstants" in the anchor to create some kind of formula that will yield the same result across all screens using division/multiplication of the main screen size (IPad, IPhone, etc.) to determine an exact similar location visually?
Something like bottomButtonView.widthAnchor.constraint(equalToConstant: -/+ 20).isActive = true
As opposed to a "fixed" variable that yields a different "visual" position across all IOS devices:
bottomButtonView.widthAnchor.constraint(equalToConstant: 400).isActive = true
I do not want to use the storyboard, as I am knee-deep in programmatically building my app. I have also heard programmatically programming your app is the way to go for easier future changes etc.
The following snippet of code is showing what I have in the ViewController that displays a red rectangle which would be great to have the same size/shape relative to the screen size (IPad, IPhone 6,7,8,X,11, etc.):
let bottomButtonView = UIView()
bottomButtonView.translatesAutoresizingMaskIntoConstraints = false
bottomButtonView.backgroundColor = .red
view.addSubview(bottomButtonView)
bottomButtonView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = false
bottomButtonView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
bottomButtonView.widthAnchor.constraint(equalToConstant: 400).isActive = true
bottomButtonView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
bottomButtonView.heightAnchor.constraint(equalToConstant: 300).isActive = true
bottomButtonView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 400).isActive = true
Thank you in advanced.

Make View visible outside TableViewCell

Is it possible to have a view inside a tableViewCell and make it visible even outside the tableView-frame?
I would need this for an animation. I tried setting clipsToBounde = false but that didn't solve the issue. The view is still cut outside the tableViewFrame.
My view inside tableViewCell:
func setupLoadingAnimation(){
successAnimation.translatesAutoresizingMaskIntoConstraints = false
successAnimation.clipsToBounds = false
self.contentView.addSubview(successAnimation)
successAnimation.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: -60).isActive = true
successAnimation.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
successAnimation.widthAnchor.constraint(equalToConstant: 160).isActive = true
successAnimation.heightAnchor.constraint(equalToConstant: 160).isActive = true
successAnimation.isHidden = true
successAnimation.loopMode = .playOnce
}
You'll need to make sure all views in the hierarchy have their clipping set to false. Start with the superview of successAnimation and go up through the hierarchy, this will include the cell's contentView and the table view itself.
Another thing you'll have to look for is that views that are added to the hierarchy later will show on top of others if they are at the same level, and since a table view manages its cells it's hard to know which cells are going to overlap your animation.
To fix this you could call bringSubviewToFront() on your table view and pass the cell, I would do this right before executing the success animation.
Another alternative would be to place the table and success views in a shared parent, that way you only have to make sure that the success view is above the table view once, when you add the views.

View doesn't appear after changing the view property 'isHidden = false'

I'm developing an iOS application and then the issue that I have faced now is showing a view using the view property isHidden.
I initialized a custom view including a CAAnimation and then set the default isHidden property true to hide. After a certain condition meets I changed the isHidden property to false to show it. But in this case the view doesn't appear.
private func setupButtonEffectView() {
self.buttonEffectView = ButtonEffectView()
self.buttonEffectView!.translatesAutoresizingMaskIntoConstraints = false
// self.view.addSubview(self.buttonEffectView!)
self.view.insertSubview(self.buttonEffectView!, belowSubview: self.button!)
NSLayoutConstraint.activate([
self.buttonEffectView!.centerXAnchor.constraint(equalTo: self.button!.centerXAnchor),
self.buttonEffectView!.centerYAnchor.constraint(equalTo: self.button!.centerYAnchor),
self.buttonEffectView!.widthAnchor.constraint(equalToConstant: 100),
self.buttonEffectView!.heightAnchor.constraint(equalToConstant: 100)
])
self.buttonEffectView!.isHidden = true
}
I created the button effect using the method above.
Try instead of hiding the view, setting the alpha to 0.0. self.buttonEffectView.alpha = 0.0. Then when you want to show it set the alpha to 1.0.

MKMapView's scale is not shown

I'm doing an iOS application. In Xcode 9.1 I create a MKMapView by
let mapView = MKMapView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))
mapView.isUserInteractionEnabled = false
mapView.mapType = .satellite
mapView.showsCompass = false
mapView.showsScale = true
view.addSubview(mapView)
but when I run it in the simulator the scale is not shown and I get three messages in the log:
Could not inset compass from edges 9
Could not inset scale from edge 9
Could not inset legal attribution from corner 4
The compass is not shown (as expected) but it's not shown if I change mapView.showsCompass to trueeither. However, the Legal link is shown. What am I missing here? I'm guessing it's something about the new safe areas introduced with iOS 11, but I fail to see how that is important for a view I want to be covering the whole screen.
In iOS 10 or lower
As #Paulw11 says, the scale is only shown while zooming by default.
In iOS 11
You can use scaleVisibility.
https://developer.apple.com/documentation/mapkit/mkscaleview/2890254-scalevisibility
let scale = MKScaleView(mapView: mapView)
scale.scaleVisibility = .visible // always visible
view.addSubview(scale)
had the same problem with the scale today. I want that scale visible all the time. Cost me several hours to solve it. So I add the code here, just in case, someone run into the same issue.
Got some hints:
from this thread: Use Safe Area Layout programmatically
and this website: Pain Free Constraints with Layout Anchors
Happy coding ...
Hardy
// "self.MapOnScreen" refers to the map currently displayed
// check if we have to deal with the scale
if #available(iOS 11.0, *) {
// as we will change the UI, ensure it's on main thread
DispatchQueue.main.async(execute: {
// switch OFF the standard scale (otherwise both will be visible when zoom in/out)
self.MapOnScreen.showsScale = false
// build the view
let scale = MKScaleView(mapView: self.MapOnScreen)
// we want to use autolayout
scale.translatesAutoresizingMaskIntoConstraints = false
// scale should be visible all the time
scale.scaleVisibility = .visible // always visible
// add it to the map
self.MapOnScreen.addSubview(scale)
// get the current safe area of the map
let guide = self.MapOnScreen.safeAreaLayoutGuide
// Activate this array of constraints, which at the time removes leftovers if any
NSLayoutConstraint.activate(
[
// LEFT (I do not want a change if right-to-left language) margin with an offset to safe area
// alternative would be ".leadingAnchor", which switches to the right margin, if right-to-left language is used
scale.leftAnchor.constraint(equalTo: guide.leftAnchor, constant: 16.0),
// right edge will be the middle of the map
scale.rightAnchor.constraint(equalTo: guide.centerXAnchor),
// top margin is the top safe area
scale.topAnchor.constraint(equalTo: guide.topAnchor),
// view will be 20 points high
scale.heightAnchor.constraint(equalToConstant: 20.0)
]
)
})
}
Objective c equivalent:-
if (#available(iOS 11.0, *)) {
// switch OFF the standard scale (otherwise both will be visible when zoom in/out)
self.map.showsScale = false;
// build the view
MKScaleView* scale = [MKScaleView scaleViewWithMapView:self.map];
// we want to use autolayout
scale.translatesAutoresizingMaskIntoConstraints = false;
// scale should be visible all the time
scale.scaleVisibility = MKFeatureVisibilityVisible;// always visible
// add it to the map
[self.view addSubview:scale];
// get the current safe area of the map
UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
// Activate this array of constraints, which at the time removes leftovers if any
[NSLayoutConstraint activateConstraints:
#[
// LEFT (I do not want a change if right-to-left language) margin with an offset to safe area
// alternative would be ".leadingAnchor", which switches to the right margin, if right-to-left language is used
//[scale.leftAnchor constraintEqualToAnchor: guide.centerXAnchor constant: -(scale.frame.size.width/2.0)],
// right edge will be the middle of the map
[scale.rightAnchor constraintEqualToAnchor: guide.centerXAnchor constant: (scale.frame.size.width/2.0)],
// top margin is the top safe area
[scale.bottomAnchor constraintEqualToAnchor: guide.bottomAnchor constant:-self.toolBar.frame.size.height],
// view will be 20 points high
[scale.heightAnchor constraintEqualToConstant: 50.0]
]
];
[self.view bringSubviewToFront:scale];
}

How to lock the scroll view in place?

I want to lock the scrollView when my segmented Control comes to top of the screen. How can I do this in swift? What's the code of this? How to compute the distance between the top of the segmented control and top of the view controller? It means how can I find the true place for locking scrollView?
After Swift 4.0 it has changed to
scrollView.isScrollEnabled = false
and
scrollView?.isScrollEnabled = true
Just flip the scrollEnabled boolean:
yourScrollView.scrollEnabled = false
To make it scroll again:
yourScrollView.scrollEnabled = true

Resources