Skip to content

Commit

Permalink
Use animated view annotation in interaction in imported style example
Browse files Browse the repository at this point in the history
  • Loading branch information
persidskiy committed Sep 23, 2024
1 parent 201b7be commit 118811f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,18 @@
"text-font": ["Open Sans ExtraBold", "Arial Unicode MS Regular"]
},
"paint": {
"text-color": [
"text-color": "hsl(220, 100%, 20%)",
"text-opacity": [
"case",
["to-boolean", ["feature-state", "active"]],
"red",
"hsl(220, 100%, 20%)"
["to-boolean", ["feature-state", "hidden"]],
0,
1
],
"icon-opacity": [
"case",
["to-boolean", ["feature-state", "hidden"]],
0,
1
]
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,36 @@ struct StandardStyleImportExample: View {
let importId = "real-estate-fragment"
StyleImport(id: importId, uri: StyleURI(url: styleURL)!)

/// The contents of the imported style are private. However if it defines the a featureset,
/// you can add an interaction handler to it.
/// The contents of the imported style are private, meaning all the implementation details such as layers and sources are not accessible at runtime.
/// However the style defines a "hotels-price" featureset that represents a portion of features available for interaction.
/// Using Interactions API you can add interactions to featuresets.
/// See `fragment-realestate-NY.json` for more information.
TapInteraction(.featureset("hotels-price", importId: importId)) { priceLabel, _ in
/// Select a price label when it's clicked
selectedPriceLabel = priceLabel
return true
}

/// An interaction without specified featureset handles all corresponding events that were haven't been handled by other interactions.
TapInteraction { _ in
/// When the user taps the map outside of the price labels, deselect the latest selected label.
selectedPriceLabel = nil
return true
}

if let selectedPriceLabel {
if let selectedPriceLabel, let coordinate = selectedPriceLabel.geometry.point?.coordinates {
/// When there's a selected price label, we use it to set a feature state.
/// The active state is implemented in `fragment-realestate-NY.json` and changes the label color to red.
FeatureState(selectedPriceLabel, state: ["active": true])
/// The `hidden` state is implemented in `fragment-realestate-NY.json` and hides label and icon.
FeatureState(selectedPriceLabel, state: ["hidden": true])

/// Instead of label we show a callout annotation with animation.
MapViewAnnotation(coordinate: coordinate) {
HotelCallout(feature: selectedPriceLabel)
/// The `id` makes the view to be re-created for each unique feature
/// so appearing animation plays each time.
.id(selectedPriceLabel.id)
}
.variableAnchors([.init(anchor: .bottom)])
}
}

Expand Down Expand Up @@ -90,6 +101,32 @@ struct StandardStyleImportExample: View {
}
}

@available (iOS 14.0, *)
private struct HotelCallout: View {
var feature: InteractiveFeature
@State private var scale: CGFloat = 0.1

var body: some View {
VStack(alignment: .leading, spacing: 2) {
Text(feature.name ?? "")
.font(.headline)
Text(feature.price ?? "")
.font(.subheadline)
.foregroundColor(.gray)
}

.padding(6)
/// For callout shape see CalloutView.swift
.callout(anchor: .bottom, color: .white, tailSize: 10)
.scaleEffect(scale, anchor: .bottom)
.onAppear {
withAnimation(Animation.interpolatingSpring(stiffness: 200, damping: 16).delay(0)) {
scale = 1.0
}
}
}
}

@available(iOS 13.0, *)
private struct NYNJBorder: MapContent {
var body: some MapContent {
Expand All @@ -111,12 +148,8 @@ private struct NYNJBorder: MapContent {
}

private extension InteractiveFeature {
var price: String? {
guard case .number(let price) = properties?["price"] else {
return nil
}
return "$ \(price)"
}
var price: String? { properties?["price"]??.number.map { "$ \($0)" } }
var name: String? { properties?["name"]??.string }
}

private let styleURL = Bundle.main.url(forResource: "fragment-realestate-NY", withExtension: "json")!
Expand Down
2 changes: 1 addition & 1 deletion Apps/Examples/Examples/SwiftUI Examples/SwiftUIRoot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct SwiftUIRoot: View {
ExampleLink("Show me the map!", note: "Just a Map().", destination: Map().ignoresSafeArea())
ExampleLink("Locate Me", note: "Use Viewport to create user location control.", destination: LocateMeExample())
ExampleLink("Locations", note: "New look of locations, configure standard style parameters.", destination: StandardStyleLocationsExample())
ExampleLink("Standard Style Import", note: "Import Mapbox Standard style into your custom style.", destination: StandardStyleImportExample())
ExampleLink("Style Imports", note: "Learn how to use style imports and add interactions to featuresets.", destination: StandardStyleImportExample())
ExampleLink("Dynamic Styling Example", note: "Use dynamic styling at runtime", destination: DynamicStylingExample())
ExampleLink("Simple Map", note: "Camera observing, automatic dark mode support.", destination: SimpleMapExample())
ExampleLink("Snapshot Map", note: "Make a snapshot of the map.", destination: SnapshotMapExample())
Expand Down

0 comments on commit 118811f

Please sign in to comment.