mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-09 15:51:05 +00:00
[ASMapNode] Add custom pin annotation for static maps (#1890)
* Adds possibility to have custom annotation pins on static map. This resolves #1889. * Removes wrong example for map annotations and adds some annotations to correct map example. #1889 * Static map node now uses specific property block to get annotation views. * Changes self to strongSelf inside of the snapshotters completion block. * MapNode: Adds statement in documentation. * MapNode: Block for annotation view/image now returns UIImage and center offset is returned in inout param. * MapNode and map example: Fixes from review. * MapNode example: Gets image directly from custom annotation, without creating annotation view.
This commit is contained in:
parent
c0be871812
commit
873bae2eed
@ -70,6 +70,12 @@ typedef NS_OPTIONS(NSUInteger, ASMapNodeShowAnnotationsOptions)
|
||||
*/
|
||||
@property (nonatomic, assign) ASMapNodeShowAnnotationsOptions showAnnotationsOptions;
|
||||
|
||||
/**
|
||||
* @abstract The block which should return annotation image for static map based on provided annotation.
|
||||
* @discussion This block is executed on an arbitrary serial queue. If this block is nil, standard pin is used.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) UIImage * _Nullable (^imageForStaticMapAnnotationBlock)(id<MKAnnotation> annotation, CGPoint *centerOffset);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -167,6 +167,14 @@
|
||||
self.options = options;
|
||||
}
|
||||
|
||||
- (void)setMapDelegate:(id<MKMapViewDelegate>)mapDelegate {
|
||||
_mapDelegate = mapDelegate;
|
||||
|
||||
if (_mapView) {
|
||||
_mapView.delegate = mapDelegate;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Snapshotter
|
||||
|
||||
- (void)takeSnapshot
|
||||
@ -209,15 +217,27 @@
|
||||
UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
|
||||
[image drawAtPoint:CGPointZero];
|
||||
|
||||
// Get a standard annotation view pin. Future implementations should use a custom annotation image property.
|
||||
MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
|
||||
UIImage *pinImage = pin.image;
|
||||
CGSize pinSize = pin.bounds.size;
|
||||
UIImage *pinImage;
|
||||
CGPoint pinCenterOffset = CGPointZero;
|
||||
|
||||
// Get a standard annotation view pin if there is no custom annotation block.
|
||||
if (!strongSelf.imageForStaticMapAnnotationBlock) {
|
||||
pinImage = [strongSelf.class defaultPinImageWithCenterOffset:&pinCenterOffset];
|
||||
}
|
||||
|
||||
for (id<MKAnnotation> annotation in annotations) {
|
||||
if (strongSelf.imageForStaticMapAnnotationBlock) {
|
||||
// Get custom annotation image from custom annotation block.
|
||||
pinImage = strongSelf.imageForStaticMapAnnotationBlock(annotation, &pinCenterOffset);
|
||||
if (!pinImage) {
|
||||
// just for case block returned nil, which can happen
|
||||
pinImage = [strongSelf.class defaultPinImageWithCenterOffset:&pinCenterOffset];
|
||||
}
|
||||
}
|
||||
|
||||
CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
|
||||
if (CGRectContainsPoint(finalImageRect, point)) {
|
||||
CGPoint pinCenterOffset = pin.centerOffset;
|
||||
CGSize pinSize = pinImage.size;
|
||||
point.x -= pinSize.width / 2.0;
|
||||
point.y -= pinSize.height / 2.0;
|
||||
point.x += pinCenterOffset.x;
|
||||
@ -235,6 +255,17 @@
|
||||
}];
|
||||
}
|
||||
|
||||
+ (UIImage *)defaultPinImageWithCenterOffset:(CGPoint *)centerOffset
|
||||
{
|
||||
static MKAnnotationView *pin;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
|
||||
});
|
||||
*centerOffset = pin.centerOffset;
|
||||
return pin.image;
|
||||
}
|
||||
|
||||
- (void)setUpSnapshotter
|
||||
{
|
||||
_snapshotter = [[MKMapSnapshotter alloc] initWithOptions:self.options];
|
||||
|
||||
@ -14,13 +14,14 @@
|
||||
694993D81C8B334F00491CA5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 694993D71C8B334F00491CA5 /* ViewController.m */; };
|
||||
694993DD1C8B334F00491CA5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 694993DC1C8B334F00491CA5 /* Assets.xcassets */; };
|
||||
694993E01C8B334F00491CA5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 694993DE1C8B334F00491CA5 /* LaunchScreen.storyboard */; };
|
||||
905C815E1D362E9400EA2625 /* CustomMapAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 905C815D1D362E9400EA2625 /* CustomMapAnnotation.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
15AD337503831C4D33FF8B3A /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
465082D55CCF1B0CB1AEBACC /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5E5E62821D13F39400D81E38 /* MapHandlerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapHandlerNode.h; sourceTree = "<group>"; };
|
||||
5E5E62831D13F39400D81E38 /* MapHandlerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MapHandlerNode.m; sourceTree = "<group>"; };
|
||||
5E5E62831D13F39400D81E38 /* MapHandlerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = MapHandlerNode.m; sourceTree = "<group>"; tabWidth = 2; };
|
||||
694993CD1C8B334F00491CA5 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
694993D11C8B334F00491CA5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
694993D31C8B334F00491CA5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
@ -30,6 +31,8 @@
|
||||
694993DC1C8B334F00491CA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
694993DF1C8B334F00491CA5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
694993E11C8B334F00491CA5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
905C815C1D362E9400EA2625 /* CustomMapAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomMapAnnotation.h; sourceTree = "<group>"; };
|
||||
905C815D1D362E9400EA2625 /* CustomMapAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomMapAnnotation.m; sourceTree = "<group>"; };
|
||||
97482F27BE2F7583EFE1BC2C /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -89,6 +92,8 @@
|
||||
694993D71C8B334F00491CA5 /* ViewController.m */,
|
||||
5E5E62821D13F39400D81E38 /* MapHandlerNode.h */,
|
||||
5E5E62831D13F39400D81E38 /* MapHandlerNode.m */,
|
||||
905C815C1D362E9400EA2625 /* CustomMapAnnotation.h */,
|
||||
905C815D1D362E9400EA2625 /* CustomMapAnnotation.m */,
|
||||
694993DC1C8B334F00491CA5 /* Assets.xcassets */,
|
||||
694993D01C8B334F00491CA5 /* Supporting Files */,
|
||||
);
|
||||
@ -229,6 +234,7 @@
|
||||
694993D81C8B334F00491CA5 /* ViewController.m in Sources */,
|
||||
694993D51C8B334F00491CA5 /* AppDelegate.m in Sources */,
|
||||
694993D21C8B334F00491CA5 /* main.m in Sources */,
|
||||
905C815E1D362E9400EA2625 /* CustomMapAnnotation.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
6
examples/ASMapNode/Sample/Assets.xcassets/Contents.json
Normal file
6
examples/ASMapNode/Sample/Assets.xcassets/Contents.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
23
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/Contents.json
vendored
Normal file
23
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "hill.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "hill@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "hill@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/hill.png
vendored
Normal file
BIN
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/hill.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
BIN
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/hill@2x.png
vendored
Normal file
BIN
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/hill@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
BIN
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/hill@3x.png
vendored
Normal file
BIN
examples/ASMapNode/Sample/Assets.xcassets/Hill.imageset/hill@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
23
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/Contents.json
vendored
Normal file
23
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "water.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "water@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "water@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/water.png
vendored
Normal file
BIN
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/water.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
BIN
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/water@2x.png
vendored
Normal file
BIN
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/water@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
BIN
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/water@3x.png
vendored
Normal file
BIN
examples/ASMapNode/Sample/Assets.xcassets/Water.imageset/water@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
28
examples/ASMapNode/Sample/CustomMapAnnotation.h
Normal file
28
examples/ASMapNode/Sample/CustomMapAnnotation.h
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// CustomMapAnnotation.h
|
||||
// ASDKMapTest
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <MapKit/MapKit.h>
|
||||
|
||||
@interface CustomMapAnnotation : NSObject<MKAnnotation>
|
||||
|
||||
@property (assign, nonatomic) CLLocationCoordinate2D coordinate;
|
||||
@property (copy, nonatomic, nullable) UIImage *image;
|
||||
@property (copy, nonatomic, nullable) NSString *title;
|
||||
@property (copy, nonatomic, nullable) NSString *subtitle;
|
||||
|
||||
@end
|
||||
22
examples/ASMapNode/Sample/CustomMapAnnotation.m
Normal file
22
examples/ASMapNode/Sample/CustomMapAnnotation.m
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// CustomMapAnnotation.m
|
||||
// ASDKMapTest
|
||||
//
|
||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import "CustomMapAnnotation.h"
|
||||
|
||||
@implementation CustomMapAnnotation
|
||||
|
||||
@end
|
||||
@ -16,6 +16,7 @@
|
||||
//
|
||||
|
||||
#import "MapHandlerNode.h"
|
||||
#import "CustomMapAnnotation.h"
|
||||
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
||||
|
||||
@ -90,6 +91,22 @@
|
||||
[_liveMapToggleButton setTitle:[self liveMapStr] withFont:nil withColor:[UIColor blueColor] forState:ASControlStateNormal];
|
||||
[_liveMapToggleButton setTitle:[self liveMapStr] withFont:[UIFont systemFontOfSize:14] withColor:[UIColor blueColor] forState:ASControlStateHighlighted];
|
||||
[_liveMapToggleButton addTarget:self action:@selector(toggleLiveMap) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||
|
||||
// avoiding retain cycles
|
||||
__weak MapHandlerNode *weakSelf = self;
|
||||
|
||||
self.mapNode.imageForStaticMapAnnotationBlock = ^UIImage *(id<MKAnnotation> annotation, CGPoint *centerOffset){
|
||||
MapHandlerNode *grabbedSelf = weakSelf;
|
||||
if (grabbedSelf) {
|
||||
if ([annotation isKindOfClass:[CustomMapAnnotation class]]) {
|
||||
CustomMapAnnotation *customAnnotation = (CustomMapAnnotation *)annotation;
|
||||
return customAnnotation.image;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
};
|
||||
|
||||
[self addAnnotations];
|
||||
}
|
||||
|
||||
#pragma mark - Layout
|
||||
@ -183,6 +200,30 @@
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (void)addAnnotations {
|
||||
|
||||
MKPointAnnotation *brno = [MKPointAnnotation new];
|
||||
brno.coordinate = CLLocationCoordinate2DMake(49.2002211, 16.6078411);
|
||||
brno.title = @"Brno city";
|
||||
|
||||
CustomMapAnnotation *atlantic = [CustomMapAnnotation new];
|
||||
atlantic.coordinate = CLLocationCoordinate2DMake(38.6442228, -29.9956942);
|
||||
atlantic.title = @"Atlantic ocean";
|
||||
atlantic.image = [UIImage imageNamed:@"Water"];
|
||||
|
||||
CustomMapAnnotation *kilimanjaro = [CustomMapAnnotation new];
|
||||
kilimanjaro.coordinate = CLLocationCoordinate2DMake(-3.075833, 37.353333);
|
||||
kilimanjaro.title = @"Kilimanjaro";
|
||||
kilimanjaro.image = [UIImage imageNamed:@"Hill"];
|
||||
|
||||
CustomMapAnnotation *mtblanc = [CustomMapAnnotation new];
|
||||
mtblanc.coordinate = CLLocationCoordinate2DMake(45.8325, 6.864444);
|
||||
mtblanc.title = @"Mont Blanc";
|
||||
mtblanc.image = [UIImage imageNamed:@"Hill"];
|
||||
|
||||
self.mapNode.annotations = @[brno, atlantic, kilimanjaro, mtblanc];
|
||||
}
|
||||
|
||||
-(NSString *)liveMapStr
|
||||
{
|
||||
return _mapNode.liveMap ? @"Live Map is ON" : @"Live Map is OFF";
|
||||
@ -235,6 +276,21 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (MKAnnotationView *)annotationViewForAnnotation:(id<MKAnnotation>)annotation
|
||||
{
|
||||
MKAnnotationView *av;
|
||||
if ([annotation isKindOfClass:[CustomMapAnnotation class]]) {
|
||||
av = [[MKAnnotationView alloc] init];
|
||||
av.centerOffset = CGPointMake(21, 21);
|
||||
av.image = [(CustomMapAnnotation *)annotation image];
|
||||
} else {
|
||||
av = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:@""];
|
||||
}
|
||||
|
||||
av.opaque = NO;
|
||||
return av;
|
||||
}
|
||||
|
||||
#pragma mark - MKMapViewDelegate
|
||||
|
||||
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
|
||||
@ -244,4 +300,9 @@
|
||||
_deltaLonEditableNode.attributedText = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%f", mapView.region.span.longitudeDelta]];
|
||||
}
|
||||
|
||||
- (MKAnnotationView *)mapView:(MKMapView *)__unused mapView viewForAnnotation:(id<MKAnnotation>)annotation
|
||||
{
|
||||
return [self annotationViewForAnnotation:annotation];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user