How to resize MKAnnotationView on iOS6? - mkmapview

Resize MKAnnotationView Image When map zooms in and out? This methord are successful on iOS5, but failed on iOS6.
I change the MKAnnotationView's transform directly, and no luck. The MKAnnotationView only resize in a flash(When touch up inside the MKMapView, after the touch up finish, the MKAnnotationView will restore the original size).
My code are below:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
for (id <MKAnnotation>annotation in _mapView.annotations) {
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
continue;
// handle our custom annotations
//
if ([annotation isKindOfClass:[XPMKAnnotation class]])
{
// try to retrieve an existing pin view first
MKAnnotationView *pinView = [_mapView viewForAnnotation:annotation];
//resize the pin view
double zoomLevel = [_mapView getZoomLevel];
double scale = (1.0 * zoomLevel / 16) + 0.5;
pinView.transform = CGAffineTransformMakeScale(scale, scale);
}
}
}
Can we resize the MKAnnotationView on iOS6? Anybody know any way?

Apple suggests resizing the .image property of an annotation view. In my case shown below, I looked at the UIImage that was set in the viewforAnnotation and re-scaled it to the zoom level in a UIPinchGestureRecognizer
UIImage *orangeImage = [UIImage imageNamed:#"Orange210.PNG"];
CGRect resizeRect;
//rescale image based on zoom level
resizeRect.size.height = orangeImage.size.height * scale;
resizeRect.size.width = orangeImage.size.width * scale ;
NSLog(#"height = %f, width = %f, zoomLevel = %f", resizeRect.size.height, resizeRect.size.width,zoomLevel );
resizeRect.origin = (CGPoint){0,0};
UIGraphicsBeginImageContext(resizeRect.size);
[orangeImage drawInRect:resizeRect];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
pinView.image = resizedImage;

Related

How do I change the background color of a tabbed page in Xamarin iOS?

I need to change the background color of the currently tabbed page in my UITabBarController. I've searched through every stackoverflow post I could find but nothing worked for me. I thought there would be something like UITabBar.Appearance.SelectedImageTintColor, just for the background color but it doesn't seem so.
For example, I want to change the color of that part when I am on the right tab:
Does someone know how to do that?
You could invoked the following code in your UITabBarController
public xxxTabBarController()
{
//...set ViewControllers
this.TabBar.BarTintColor = UIColor.Red;
}
Update
//3.0 here is if you have three child page in tab , set it as the current value in your project
//
var size = new CGSize(TabBar.Frame.Width / 3.0, IsFullScreen());
this.TabBar.SelectionIndicatorImage = ImageWithColor(size,UIColor.Green);
double IsFullScreen()
{
double height = 64;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 84;
}
}
return height;
}
UIImage ImageWithColor(CGSize size, UIColor color)
{
var rect = new CGRect(0, 0, size.Width, size.Height);
UIGraphics.BeginImageContextWithOptions(size, false, 0);
CGContext context = UIGraphics.GetCurrentContext();
context.SetFillColor(color.CGColor);
context.FillRect(rect);
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image;
}
The trick is to use the SelectionIndicatorImage Property of the UITabBar and generate a completely filled image with your desired color using the following method:
private UIImage ImageWithColor(CGSize size)
{
CGRect rect = new CGRect(0, 0, size.Width, size.Height);
UIGraphics.BeginImageContext(size);
using (CGContext context = UIGraphics.GetCurrentContext())
{
context.SetFillColor(UIColor.Green); //change color if necessary
context.FillRect(rect);
}
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image;
}
To initialize everything we override ViewWillLayoutSubviews() like this:
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
// The tabbar height will always be 49 unless we force it to reevaluate it's size on runtime ...
myTabBar.InvalidateIntrinsicContentSize();
double height = myTabBar.Frame.Height;
CGSize size = new CGSize(new nfloat(myTabBar.Frame.Width / myTabBar.Items.Length, height));
// Now get our all-green image...
UIImage image = ImageWithColor(size);
// And set it as the selection indicator
myTabBar.SelectionIndicatorImage = image;
}
As mentioned in this article (google translating it step by step when necessary lol) calling InvalidateIntrinsicContentSize() will force the UITabBar to reevaluate it's size and will get you the actual runtime height of the tab bar (instead of the constant 49 height value from XCode).

UIGraphicsBeginImageContext created image stays in memory forever

I'm creating many colour variations of an image using Core Graphics. I need to create about 320 in total but gradually, the memory usage of the app keeps increasing until it crashes. From Instruments, I see that more CGImage objects are being created and stay alive. I want to release them because I store the images to the cache directory in PNG format.
I have searched through all other solutions I could find without success. Any help is appreciated. Thanks.
Here's the main part:
+(UIImage *)tintedImageFromImage:(UIImage *)sourceImage colour:(UIColor *)color intensity:(float)intensity {
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(sourceImage.size, NO, 0.0);
} else {
UIGraphicsBeginImageContext(sourceImage.size);
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height);
// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, sourceImage.CGImage);
// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[color setFill];
CGContextFillRect(context, rect);
//Set the original greyscale template as the overlay of the new image
sourceImage = [self verticallyFlipImage:sourceImage];
[sourceImage drawInRect:CGRectMake(0,0, sourceImage.size.width,sourceImage.size.height) blendMode:kCGBlendModeMultiply alpha:intensity];
UIImage *colouredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
colouredImage = [self verticallyFlipImage:colouredImage];
return colouredImage;
}
this is used to flip the image:
+(UIImage *)verticallyFlipImage:(UIImage *)originalImage {
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:originalImage];
UIGraphicsBeginImageContext(tempImageView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, tempImageView.frame.size.height);
CGContextConcatCTM(context, flipVertical);
[tempImageView.layer renderInContext:context];
UIImage *flippedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return flippedImage;
}
Add to verticallyFlipImage the line tempImageView.image = nil; in order to make the image view release the image. This solves the problem.

MKMapView image overlay drawing inverted

I am currently creating an app which requires numerous overlays of different sizes to be drawn on a map. The app currently grabs 2 map points which represent the corners of a bounding box in which the overlay should sit. I am then converting these in to a MKMapRect for use within an MKOverlay class. The overlay is drawing in the correct place but the image seems to be flipped vertically, I can tell this as I tried applying a CGAffineTransformMakeRotation(180) and the image appeared the right way around but the writing was backwards.
If anyone can help me figure out why it's doing this it would be much appreciated, please see my code below.
Setup code:
// First grab the overlay co-ordinates
double left = [[self.storedWildMapObject.arrayBBox objectAtIndex:0] doubleValue], bottom = [[self.storedWildMapObject.arrayBBox objectAtIndex:1] doubleValue], right = [[self.storedWildMapObject.arrayBBox objectAtIndex:2] doubleValue], top = [[self.storedWildMapObject.arrayBBox objectAtIndex:3] doubleValue];
// Store these in 2 coordinates representing top left / bot right
CLLocationCoordinate2D upperLeftCoord =
CLLocationCoordinate2DMake(top,left);
CLLocationCoordinate2D lowerRightCoord =
CLLocationCoordinate2DMake(bottom,right);
//Convert to map points
MKMapPoint upperLeft = MKMapPointForCoordinate(upperLeftCoord);
MKMapPoint lowerRight = MKMapPointForCoordinate(lowerRightCoord);
// Work out sizes
double rightToLeftDiff = lowerRight.y - upperLeft.y;
double topToBottDiff = lowerRight.x - upperLeft.x;
MKMapRect bounds = MKMapRectMake(upperLeft.x, upperLeft.y, topToBottDiff, rightToLeftDiff);
// Add to overlay
MKMapOverlay *mapOverlay = [[MKMapOverlay alloc] initWithMapRect:bounds andCoord:upperLeftCoord];
[self.mapV addOverlay:mapOverlay];
// Map overlay
- (id)initWithMapRect:(MKMapRect)rect andCoord:(CLLocationCoordinate2D)coord
{
self = [super init];
if (self)
{
self.centerPos = coord;
self.mkMapRect = rect;
}
return self;
}
-(CLLocationCoordinate2D)coordinate
{
return self.centerPos;
}
- (MKMapRect)boundingMapRect
{
return self.mkMapRect;
}
// MapOverlayView
- (id)initWithOverlay:(id <MKOverlay>)overlay andImage:(UIImage *)img
{
self = [super initWithOverlay:overlay];
if (self)
{
self.image = img;
}
return self;
}
/** Degrees to Radian **/
#define degreesToRadians( degrees ) ( ( degrees ) / 180.0 * M_PI )
/** Radians to Degrees **/
#define radiansToDegrees( radians ) ( ( radians ) * ( 180.0 / M_PI ) )
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)ctx
{
CGImageRef imageReference = self.image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGRect clipRect = [self rectForMapRect:mapRect];
CGContextAddRect(ctx, clipRect);
CGContextClip(ctx);
//CGContextRotateCTM(ctx, degreesToRadians(180.0f));
CGContextDrawImage(ctx, theRect, imageReference);
}
Just incase it helps I also have a debugger print out of theMapRect as used in MapOverlayView:
(lldb) p theMapRect
(MKMapRect) $17 = {
(MKMapPoint) origin = {
(double) x = 1.27662e+08
(double) y = 7.86099e+07
}
(MKMapSize) size = {
(double) width = 8.12378e+06
(double) height = 1.27474e+07
}
}
Below is what it looks like:
Have you verified that the storedwildmapobject has the coordinates in the order you are expecting them?
The answer found here seems to draw my image the correct way around with the same mapRect:
https://stackoverflow.com/a/3599448/1090024
So I'm using this for now.

CALayer as SubLayer Not Visible

I am trying to built an animated circle which would be drawn clockwise until it becomes complete circle as illustrated in iPhone Core Animation - Drawing a Circle
Problem is that CALayer object is not added or build. I tested and saw that it is not accessing my drawInContext:CGContextRef and animatingArc methods.
What so far I have done is:
In AnimateArc.h
#interface AnimateArc : CALayer {
CAShapeLayer *circle;
}
-(void) animatingArc;
#end
In AnimateArc.m
-(void) drawInContext:(CGContextRef)ctx
{
CGFloat radius = 50.0;
circle = [CAShapeLayer layer];
//make a circular shape
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.0, 0.0, 2 * radius, 2 * radius) cornerRadius:radius].CGPath;
CGPoint centerPoint = CGPointMake(CGRectGetWidth(self.bounds)/2, CGRectGetHeight(self.bounds)/2);
//center the shape in self.view
circle.position = centerPoint;
//configure appearence of circle
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor blackColor].CGColor;
circle.lineWidth = 5;
/*CGPointMake((self.contentsCenter.size.width), (self.contentsCenter.size.height));*/
//path the circle
CGContextAddArc(ctx, centerPoint.x, centerPoint.y, radius, 0.0, 2 * M_PI, 0);
CGContextClosePath(ctx);
//fill it
CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextFillPath(ctx); }
///////////////////////////////////////////////////////////////////////
-(void) animatingArc
{
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"arcEnd"];
anim.duration = 20.0; //animate over 20 seconds
anim.repeatCount = 1.0; //animate only once
anim.removedOnCompletion = NO; //Reamin there after completion
//animate from start to end
anim.fromValue = [NSNumber numberWithFloat:50.0f];
anim.toValue = [NSNumber numberWithFloat:150.0f];
//experiment with timing to get appearence to look the way you want
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
//add animation to circle
[circle addAnimation:anim forKey:#"animatingArc"];
}
/////////////////////
//needed since key not part of animatable properties
+(BOOL) needsDisplayForKey:(NSString *)key
{
if([key isEqualToString:#"arcEnd"])
return YES;
else
return [super needsDisplayForKey:key];
}
//ensure custom properties copied to presentation layer
-(id) initWithLayer:(id)layer
{
if((self = [super initWithLayer:layer]))
{
if ([layer isKindOfClass:[AnimateArc class]])
{
AnimateArc *other = (AnimateArc *) layer;
[other setNeedsDisplay];
}
}
return self; }
And finally in my viewController,
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view.layer addSublayer:AnimateArcObject];
[AnimateArcObject animatingArc];
}
Apology for bad formatting.... Please can someone tell me what am I doing wrong? I have also doubt that my code can crash at any place after accessing those two functions since I am novice about Core Animation and haven't got any idea that I am in right direction or not.
Any help will be appreciated. Thanks.
From my painful experience with CoreAnimation, you must always set the bounds property of any CALayer you instantiate.
So, you're layer is not showing because you are missing something like:
layer.bounds = CGRectMake(0, 0, width, height);
you should place this as soon as you instantiate the layer, and make it a habit to do so, so you don't fall into it again.
As for your code crashing, sorry. It's too distributed and I am not sure how it's linked together, so I can't help you there.
After little searching, I thought that I am going in wrong direction. So I deleted this AnimateArc file and added new one which is inheriting from UIViewController.
Then in viewDidLoad Method, I wrote the code from this link to create circle and animations using path.
In parent view controller, I added AnimatedArc ViewController's subview. Now its working perfectly :)

iAds in a Scrolling View

In my application I want to show iAd in table view controller which have both navigation bar and Tab bar. I am able to show iAd in my application but this iAd is give trouble when I try to scroll, the problem is that iAd is also scrolling with the cells due to which I am not able to view the cell in bottom. I am creating the iAd using below code. can some one help me out in resolving following issue.
#pragma mark -
#pragma mark === Banner View Methods ===
#pragma mark -
- (void)createBannerView {
Class cls = NSClassFromString(#"ADBannerView");
if (cls) {
ADBannerView *adView = [[cls alloc] initWithFrame:CGRectZero];
adView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait,
ADBannerContentSizeIdentifierLandscape, nil];
// Set the current size based on device orientation
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
adView.delegate = self;
adView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
// Set intital frame to be offscreen
CGRect bannerFrame =adView.frame;
bannerFrame.origin.y = self.view.frame.size.height;
adView.frame = bannerFrame;
self.bannerView = adView;
[self.view addSubview:adView];
[adView release];
}
}
- (void)showBanner {
CGFloat fullViewHeight = self.view.frame.size.height;
CGRect tableFrame = self.tv.frame;
CGRect bannerFrame = self.bannerView.frame;
// Shrink the tableview to create space for banner
tableFrame.size.height = fullViewHeight - bannerFrame.size.height;
// Move banner onscreen
bannerFrame.origin.y = fullViewHeight - bannerFrame.size.height;
[UIView beginAnimations:#"showBanner" context:NULL];
self.tv.frame = tableFrame;
self.bannerView.frame = bannerFrame;
[UIView commitAnimations];
}
- (void)hideBanner {
// Grow the tableview to occupy space left by banner
CGFloat fullViewHeight = self.view.frame.size.height;
CGRect tableFrame = self.tv.frame;
tableFrame.size.height = fullViewHeight;
// Move the banner view offscreen
CGRect bannerFrame = self.bannerView.frame;
bannerFrame.origin.y = fullViewHeight;
self.tv.frame = tableFrame;
self.bannerView.frame = bannerFrame;
}
- (void)releaseBanner {
if (self.bannerView) {
bannerView.delegate = nil;
self.bannerView = nil;
}
}
- (void)changeBannerOrientation:(UIInterfaceOrientation)toOrientation {
if (UIInterfaceOrientationIsLandscape(toOrientation)) {
self.bannerView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierLandscape;
}
else {
self.bannerView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierPortrait;
}
}
#pragma mark -
#pragma mark === ADBannerViewDelegate Methods ===
#pragma mark -
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
[self showBanner];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[self hideBanner];
}
yes i got it you use addSubView which i think is wrong Add this Banner in last cell of a tableview or in a fotter of a table view if you are not use load more functionalty in you app
– tableView:viewForFooterInSection:
use that delegate method of table view UItableViewDelegate i think it helps you
– tableView:heightForFooterInSection:
add that method too to specify the height of footer of your table
add the calculate banner size code in
– tableView:heightForFooterInSection:
and add banner in – tableView:heightForFooterInSection:

Resources