-
Notifications
You must be signed in to change notification settings - Fork 12
Mhd/refactor compass action #286
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
Changes from 16 commits
7898052
5ca7dba
8e6b821
21b0a02
a6f8cfc
b7e130b
6435d32
ad90150
38c0f09
13ebe9f
e59a4f5
4d91afe
3ef79b6
2df1541
c16eb88
c2b6d55
0a202c1
a759615
a067be9
64d9acc
6788766
2bc8a8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,8 @@ The ArcGIS Maps SDK for Swift currently supports rotating MapViews and SceneView | |
|
||
Compass: | ||
|
||
- Can be configured to automatically hide when the rotation is zero. | ||
- Automatically hides when the rotation is zero. | ||
- Can be configured to be always visible. | ||
- Will reset the map/scene rotation to North when tapped on. | ||
|
||
## Key properties | ||
|
@@ -23,9 +24,8 @@ Compass: | |
/// direction toward true East, etc.). | ||
/// - Parameters: | ||
/// - heading: The heading of the compass. | ||
/// - autoHide: A Boolean value that determines whether the compass | ||
/// automatically hides itself when the heading is `0`. | ||
public init(heading: Binding<Double>, autoHide: Bool = true) | ||
/// - action: An action to perform when the compass is tapped. | ||
public init(heading: Binding<Double>, action: (() async -> Void)? = nil) | ||
``` | ||
|
||
```swift | ||
|
@@ -35,27 +35,26 @@ Compass: | |
/// - Parameters: | ||
/// - viewpointRotation: The viewpoint rotation whose value determines the | ||
/// heading of the compass. | ||
/// - autoHide: A Boolean value that determines whether the compass | ||
/// automatically hides itself when the viewpoint rotation is 0 degrees. | ||
public init(viewpointRotation: Binding<Double>, autoHide: Bool = true) | ||
/// - action: An action to perform when the compass is tapped. | ||
public init(viewpointRotation: Binding<Double>, action: (() async -> Void)? = nil) | ||
mhdostal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
```swift | ||
/// Creates a compass with a binding to an optional viewpoint. | ||
/// - Parameters: | ||
/// - viewpoint: The viewpoint whose rotation determines the heading of the compass. | ||
/// - autoHide: A Boolean value that determines whether the compass automatically hides itself | ||
/// when the viewpoint's rotation is 0 degrees. | ||
public init(viewpoint: Binding<Viewpoint?>, autoHide: Bool = true) | ||
/// - action: An action to perform when the compass is tapped. | ||
public init(viewpoint: Binding<Viewpoint?>, action: (() async -> Void)? = nil) | ||
mhdostal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
`Compass` has the following modifier: | ||
`Compass` has the following modifiers: | ||
|
||
- `func compassSize(size: CGFloat)` - The size of the `Compass`, specifying both the width and height of the compass. | ||
- `func automaticallyHides(newAutomaticallyHides: Bool)` - Specifies whether the ``Compass`` should automatically hide when the heading is 0. | ||
mhdostal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Behavior: | ||
|
||
Whenever the map is not orientated North (non-zero bearing) the compass appears. When reset to north, it disappears. An initializer argument allows you to disable the auto-hide feature so that it always appears. | ||
Whenever the map is not orientated North (non-zero bearing) the compass appears. When reset to north, it disappears. The `automaticallyHides` view modifier allows you to disable the auto-hide feature so that it is always displayed. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be OK. @dfeinzimer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
When the compass is tapped, the map orients back to north (zero bearing). | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,21 +17,24 @@ import SwiftUI | |
/// A `Compass` (alias North arrow) shows where north is in a `MapView` or | ||
/// `SceneView`. | ||
public struct Compass: View { | ||
/// A Boolean value indicating whether the compass should automatically | ||
/// hide/show itself when the heading is `0`. | ||
private let autoHide: Bool | ||
|
||
/// The opacity of the compass. | ||
@State private var opacity: Double = .zero | ||
|
||
/// An action to perform when the compass is tapped. | ||
private let action: (() async -> Void)? | ||
mhdostal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// A Boolean value indicating whether the compass should automatically | ||
/// hide/show itself when the heading is `0`. | ||
private var autoHide: Bool = true | ||
|
||
/// A Boolean value indicating whether the compass should hide based on the | ||
/// current heading and whether the compass automatically hides. | ||
var shouldHide: Bool { | ||
(heading.isZero || heading.isNaN) && autoHide | ||
} | ||
|
||
/// The width and height of the compass. | ||
var size: CGFloat = 44 | ||
private var size: CGFloat = 44 | ||
|
||
/// The heading of the compass in degrees. | ||
@Binding private var heading: Double | ||
|
@@ -41,14 +44,13 @@ public struct Compass: View { | |
/// direction toward true East, etc.). | ||
/// - Parameters: | ||
/// - heading: The heading of the compass. | ||
/// - autoHide: A Boolean value that determines whether the compass | ||
/// automatically hides itself when the heading is `0`. | ||
/// - action: An action to perform when the compass is tapped. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. some doc about when you need to specify this action might be helpful to the user. For example, does the compass set the heading to zero and call the action if I have an action set? What is the behavior when no action is set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default is to rotate the map view to zero, but without animation. We'll update the doc. |
||
public init( | ||
heading: Binding<Double>, | ||
autoHide: Bool = true | ||
action: (() async -> Void)? = nil | ||
) { | ||
_heading = heading | ||
self.autoHide = autoHide | ||
self.action = action | ||
} | ||
|
||
public var body: some View { | ||
|
@@ -60,16 +62,22 @@ public struct Compass: View { | |
} | ||
.aspectRatio(1, contentMode: .fit) | ||
.opacity(opacity) | ||
.onTapGesture { heading = .zero } | ||
.frame(width: size, height: size) | ||
.onAppear { opacity = shouldHide ? 0 : 1 } | ||
.onChange(of: heading) { _ in | ||
let newOpacity: Double = shouldHide ? .zero : 1 | ||
guard opacity != newOpacity else { return } | ||
withAnimation(.default.delay(shouldHide ? 0.25 : 0)) { | ||
opacity = newOpacity | ||
} | ||
} | ||
.onAppear { opacity = shouldHide ? 0 : 1 } | ||
.onTapGesture { | ||
if let action { | ||
Task { await action() } | ||
} else { | ||
heading = .zero | ||
} | ||
} | ||
.accessibilityLabel("Compass, heading \(Int(heading.rounded())) degrees \(CompassDirection(heading).rawValue)") | ||
} | ||
} | ||
|
@@ -82,28 +90,27 @@ public extension Compass { | |
/// - Parameters: | ||
/// - viewpointRotation: The viewpoint rotation whose value determines the | ||
/// heading of the compass. | ||
/// - autoHide: A Boolean value that determines whether the compass | ||
/// automatically hides itself when the viewpoint rotation is 0 degrees. | ||
/// - action: An action to perform when the compass is tapped. | ||
init( | ||
viewpointRotation: Binding<Double>, | ||
autoHide: Bool = true | ||
action: (() async -> Void)? = nil | ||
) { | ||
let heading = Binding(get: { | ||
viewpointRotation.wrappedValue.isZero ? .zero : 360 - viewpointRotation.wrappedValue | ||
}, set: { newHeading in | ||
viewpointRotation.wrappedValue = newHeading.isZero ? .zero : 360 - newHeading | ||
}) | ||
self.init(heading: heading, autoHide: autoHide) | ||
self.init(heading: heading, action: action) | ||
} | ||
|
||
/// Creates a compass with a binding to an optional viewpoint. | ||
/// - Parameters: | ||
/// - viewpoint: The viewpoint whose rotation determines the heading of the compass. | ||
/// - autoHide: A Boolean value that determines whether the compass automatically hides itself | ||
/// - action: An action to perform when the compass is tapped. | ||
/// when the viewpoint's rotation is 0 degrees. | ||
init( | ||
viewpoint: Binding<Viewpoint?>, | ||
autoHide: Bool = true | ||
action: (() async -> Void)? = nil | ||
) { | ||
let viewpointRotation = Binding { | ||
viewpoint.wrappedValue?.rotation ?? .nan | ||
|
@@ -115,7 +122,7 @@ public extension Compass { | |
rotation: newViewpointRotation | ||
) | ||
} | ||
self.init(viewpointRotation: viewpointRotation, autoHide: autoHide) | ||
self.init(viewpointRotation: viewpointRotation, action: action) | ||
} | ||
|
||
/// Define a custom size for the compass. | ||
|
@@ -125,4 +132,13 @@ public extension Compass { | |
copy.size = size | ||
return copy | ||
} | ||
|
||
/// Specifies whether the ``Compass`` should automatically hide when the heading is 0. | ||
/// - Parameter newAutomaticallyHides: A Boolean value indicating whether the compass should automatically | ||
/// hide/show itself when the heading is `0`. | ||
func automaticallyHides(_ newAutomaticallyHides: Bool) -> some View { | ||
mhdostal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
var copy = self | ||
copy.autoHide = newAutomaticallyHides | ||
return copy | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Copyright 2023 Esri. | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import ArcGIS | ||
|
||
public extension Viewpoint { | ||
/// Creates a new viewpoint with the same target geometry and scale but with a new rotation. | ||
/// - Parameter rotation: The rotation for the new viewpoint. | ||
/// - Returns: A new viewpoint. | ||
func withRotation(_ rotation: Double) -> Viewpoint { | ||
switch self.kind { | ||
case .centerAndScale: | ||
return Viewpoint( | ||
center: self.targetGeometry as! Point, | ||
scale: self.targetScale, | ||
rotation: rotation | ||
) | ||
case.boundingGeometry: | ||
return Viewpoint( | ||
boundingGeometry: self.targetGeometry, | ||
rotation: rotation | ||
) | ||
} | ||
} | ||
} | ||
mhdostal marked this conversation as resolved.
Show resolved
Hide resolved
|
Uh oh!
There was an error while loading. Please reload this page.