Just started to use Xcode 9 and iOS 11 today, I found there is border line created about 3 px above the bottom of navigation bar. I never seen same thing in iOS 10. Any idea how to remove it? To make it clear it is not the iPhone X home button in the screenshot below, but the line in the navigation bar
I found the answer: there is a bottom shadow line created by the navigation bar which can't be accessed directly, and I have to write code replace the image for that shadow. For anyone run into the same problem, this is the code:
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"11.0")) {
// Remove navigation bar bottom shadow line in iOS 11
[self.navigationBar setBackgroundImage:[self generateSinglePixelImageWithColor:[FillrThemeManager sharedInstance].theme.fillViewNavigationBarTintColor] forBarMetrics:UIBarMetricsDefault];
self.navigationBar.shadowImage = [self generateSinglePixelImageWithColor:[UIColor clearColor]];
}
- (UIImage *)generateSinglePixelImageWithColor:(UIColor *)color {
CGSize imageSize = CGSizeMake(1.0f, 1.0f);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0f);
CGContextRef theContext = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(theContext, color.CGColor);
CGContextFillRect(theContext, CGRectMake(0.0f, 0.0f, imageSize.width, imageSize.height));
CGImageRef theCGImage = CGBitmapContextCreateImage(theContext);
UIImage *theImage;
if ([[UIImage class] respondsToSelector:#selector(imageWithCGImage:scale:orientation:)]) {
theImage = [UIImage imageWithCGImage:theCGImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
} else {
theImage = [UIImage imageWithCGImage:theCGImage];
}
CGImageRelease(theCGImage);
return theImage;
}
Related
So, I am taking a screenshot of a subclassed UIView that I save into the device's photo stream.
Problem:
The problem is that I use resizableImageWithCapInsets to add a stretched background to my UIView, but this background gets cut off on the right side and I have no idea why. If someone could help me out it would be highly appreciated.
I add the stretched background to my UIView the following way:
[diagramBase addSubview:[self addTileBackgroundOfSize:diagramBase.frame
andType:#"ipad_diagram_border.png"]];
Which calls this method:
- (UIImageView *) addTileBackgroundOfSize:(CGRect)frame
andType:(NSString *)type
{
frame.origin.x = 0.0f;
frame.origin.y = 0.0f;
UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:frame];
UIImage *image = [UIImage imageNamed:type];
UIEdgeInsets insets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f);
UIImage *backgroundImage = [image resizableImageWithCapInsets:insets];
backgroundView.image = backgroundImage;
return backgroundView;
}
The actual printscreen is done with this method (RINDiagramView is the name of my subclassed UIView, which I am taking a screenshot of). The rotation is in there because I need the image rotated when I save it, but I commented out that part and that is not what does the background to act weird.
- (UIImage *) createSnapshotOfView:(RINDiagram *) view
{
CGRect rect = [view bounds];
rect.size.height = rect.size.height - 81.0f;
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[view.layer renderInContext:context];
UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *finalImage = [[UIImage alloc] initWithCGImage: capturedScreen.CGImage
scale: 1.0
orientation: UIImageOrientationLeft];
return finalImage;
}
I use Xcode 5.1 and everything is done programmatically (no storyboard and such). The base SDK is iOS 7.1.
If you're doing iOS 7+ you can use the new drawViewHierarchyInRect:afterScreenUpdates: and related methods which Apple says are really performant.
Even if you're targeting iOS 6 you should give it a try to see if you get the same problem.
Try using the correct scale?
UIImage *finalImage = [[UIImage alloc] initWithCGImage: capturedScreen.CGImage
scale: [[UIScreen mainScreen] scale]
orientation: UIImageOrientationLeft];
Use a different UIViewContentMode?
UIViewContentModeScaleToFill -> check if you can see the edges
UIViewContentModeScaleAspectFit -> check if you can see the edges, even if position is incorrect
UIViewContentModeScaleAspectFill -> check for edge right side
The reason you got a right-side cut image is caused by this line
UIImage *finalImage = [[UIImage alloc] initWithCGImage: capturedScreen.CGImage
scale: 1.0
orientation: UIImageOrientationLeft];
You made the image orientation to left, the context will thought the left-side is your top-side.And your size has a minus to the height value, so the result turns to the right-side is cut.
About the rotation, I added some code into your code.Hopes it is helpful.
- (UIImage *) createSnapshotOfView:(UIView *) view
{
CGRect rect = [view bounds];
rect.size.height = rect.size.height - 81.0f;
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
view.transform = CGAffineTransformMakeRotation(M_PI_2);
[view.layer renderInContext:context];
UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *finalImage = [[UIImage alloc] initWithCGImage: capturedScreen.CGImage
scale: 1.0
orientation: UIImageOrientationLeft];
view.transform = CGAffineTransformMakeRotation(0);
return finalImage;
}
UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:#"foo.png" atomically:YES];
for retina display, change the first line into this:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(self.window.bounds.size);
adjust your size, may you get help..
I tried to draw a custom UINavigationBar via drawRect on iOS7. With the changes of the Navigationbar and the Statusbar my draw begins on y-origin 20.0, not on my 0.0 behind the Statusbar. I checked the wwdc videos but I only found examples with images not with custom draw. Any ideas? Do I need to set some parameters in my subclass?
create a new project based on "Master-Detail Application"
create a sublass for UINavigationBar
change the UINavigationBar in Main.storyboard to the custom class
turn off translucent [self setTranslucent:NO];
add a real simple drawRect to the sublass of UINavigationBar
I made a simple test:
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
UIBezierPath* maskPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0, 320, 64)];
[maskPath closePath];
[[UIColor greenColor] setFill];
[maskPath fill];
CGColorSpaceRelease(colorSpace);
The green NavigationBar begins under the Statusbar, how can I draw by starting behind the Statusbar?
CURRENT SOLUTION:
#Redwarp posted one way, I made also a simple version to test:
CustomBGView *testView = [[CustomBGView alloc] initWithFrame:CGRectMake(0, 0, 320, 64)];
RetinaAwareUIGraphicsBeginImageContext(testView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[testView.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBackgroundImage:image forBarPosition:UIBarPositionTop barMetrics:UIBarMetricsDefault];
Inside the custom UIView you can draw like you want and your custom view appears also behind the StatusBar.
I found a solution, which is a bit peculiar : I subclass the UINavigationBar, and in the onLayoutSubviews, I create the background I want to create, and set it as background image. So I do the equivalent of the drawRect, but in a UIImage that I set as background.
Then, in the xib or storyboard, I select my subclass as the type of the Navigation bar.
Here goes :
#implementation MyNavigationBar
- (void)layoutSubviews {
[super layoutSubviews];
CGPoint origin = [self.superview convertPoint:self.frame.origin toView:nil];
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.bounds.size.width, self.bounds.size.height + origin.y), NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClipToRect(context, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height + origin.y));
[self.baseImage drawInRect:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
UIImage *backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];
// If you don't want the bar shadow, set the shadow image as null
[self setShadowImage:[UIImage new]];
}
And whenever you wan't to change the image, you call [navigationBar needsLayout], and it will call layoutSubviews again
EDIT : The trick is getting the origin of the nav bar. If there is a status bar, the origin will be of y 20. If no status bar, it will be 0. So you add the origin.y to the height of the image your drawing into, and you will have a nice result.
This question already has answers here:
iOS Screenshot part of the screen
(4 answers)
Closed 8 years ago.
i m using this codes for screen capture for iOS:
CGImageRef screen = UIGetScreenImage();
UIImage *image = [UIImage imageWithCGImage:screen];
CGImageRelease(screen);
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
CGRect screenshotFrame;
CGImageRef screenshotRef = CGImageCreateWithImageInRect(screenshotRef, screenshotFrame);
UIImage * screenshot = [[(UIImage *)screenshotRef retain] autorelease];
CGImageRelease(screenshotRef);
But my screen contain tool bar bottom of the screen.i don't want tool bar on my captured screen. How can i crop tool bar ? How can i modified my code ?
I think you can capture the layer of self.view because it the root view
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
//Retina display
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
} else {
UIGraphicsBeginImageContext(self.view.bounds.size);
}
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Have fun!
Try this:
UIGraphicsBeginImageContext(/*CGRECT*/);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Here in CGRect pass your rect which you want to take screenshot.
Hope it helps you..
Set your
CGRect screenshotFrame = CGRectMake(0, 0, 320, 436);
// 480(screen height) - 44(toolbar height) = 436
I want to make a clean white Design. So, I set the tintColor property to whiteColor, but there are these dark Lines under the UINavigationBar and UISearchBar.
Do some one know, how to remove the dark Lines or how to change the Color?
add a method to UIImage by category
+ (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
and just set
[self.navigationController.navigationBar setShadowImage:[UIImage imageWithColor:[UIColor whiteColor]]];
This is what I did, and seemed to work, it is a further development of this link. I changed the explicit width declaration to a dynamic one, so that it will be the size of the view if you change view size or not:
UIView *overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 43, self.view.frame.size.width, 1)];
[overlayView setBackgroundColor:[UIColor whiteColor]];
[navBar addSubview:overlayView]; // navBar is your UINavigationBar instance
[overlayView release];
I found the stuff here:
How to remove UINavigatonItem's border line
From iOS 7 UINavigationBar has a shadowImage property that you can set to nil.
I've got a problem with an custom UIBarButtonItem. When I create an custom UIBarButtonItem via
[[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:#"FilterIcon.png"] style:UIBarButtonItemStyleBordered target:self action:#selector(filterTouched:)];
the resulting button does not have the "embossed" look, that the system items achieve by placing a semi-transparent black shadow behind their icons.
On the left you see the "Organize" system bar button item, rightthe result of the code from above.
Creating the shadow in the resource is futile, because iOS/Cocoa only used the mask of the image and discards any color information.
Interestingly, if I create the bar button item in the Interface-Builder it looks fine. However, in the context of my problem, I need to create the button item in code.
There is Objective-C version of James Furey's script.
- (UIImage *)applyToolbarButtonStyling:(UIImage *)oldImage {
float shadowOffset = 1;
float shadowOpacity = .54;
CGRect imageRect = CGRectMake(0, 0, oldImage.size.width, oldImage.size.height);
CGRect shadowRect = CGRectMake(0, shadowOffset, oldImage.size.width, oldImage.size.height);
CGRect newRect = CGRectUnion(imageRect, shadowRect);
UIGraphicsBeginImageContextWithOptions(newRect.size, NO, oldImage.scale);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -(newRect.size.height));
CGContextSaveGState(ctx);
CGContextClipToMask(ctx, shadowRect, oldImage.CGImage);
CGContextSetFillColorWithColor(ctx, [UIColor colorWithWhite:0 alpha:shadowOpacity].CGColor);
CGContextFillRect(ctx, shadowRect);
CGContextRestoreGState(ctx);
CGContextClipToMask(ctx, imageRect, oldImage.CGImage);
CGContextSetFillColorWithColor(ctx, [UIColor colorWithWhite:1 alpha:1].CGColor);
CGContextFillRect(ctx, imageRect);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I think the reason this occurs is covered by these answers to another question:
https://stackoverflow.com/a/3476424/1210490
https://stackoverflow.com/a/6528603/1210490
UIBarButtonItems behave differently depending on where you programmatically attach them. If you attach them to a toolbar, they'll become white "embossed" icons. If you attach them to a navigation bar, they won't.
I've spent the last few hours writing a function to apply toolbar UIBarButtonItem styling to UIImages. It's written in C# for MonoTouch, but I'm sure you'll be able to tweak it to Obj-C no problemo...
UIImage ApplyToolbarButtonStyling(UIImage oldImage)
{
float shadowOffset = 1f;
float shadowOpacity = .54f;
RectangleF imageRect = new RectangleF(PointF.Empty, oldImage.Size);
RectangleF shadowRect = new RectangleF(new PointF(0, shadowOffset), oldImage.Size);
RectangleF newRect = RectangleF.Union(imageRect, shadowRect);
UIGraphics.BeginImageContextWithOptions(newRect.Size, false, oldImage.CurrentScale);
CGContext ctxt = UIGraphics.GetCurrentContext();
ctxt.ScaleCTM(1f, -1f);
ctxt.TranslateCTM(0, -newRect.Size.Height);
ctxt.SaveState();
ctxt.ClipToMask(shadowRect, oldImage.CGImage);
ctxt.SetFillColor(UIColor.FromWhiteAlpha(0f, shadowOpacity).CGColor);
ctxt.FillRect(shadowRect);
ctxt.RestoreState();
ctxt.ClipToMask(imageRect, oldImage.CGImage);
ctxt.SetFillColor(UIColor.FromWhiteAlpha(1f, 1f).CGColor);
ctxt.FillRect(imageRect);
UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return newImage;
}
So, a UIBarButtonItem that used to look like this:
Created instead with the function above, like this:
UIBarButtonItem barButtonItem = new UIBarButtonItem(ApplyToolbarButtonStyling(UIImage.FromFile("MusicIcon.png")), UIBarButtonItemStyle.Plain, delegate {});
Would now look like this:
Hope this helps someone in the future.
Take note of the shadow offset in James Furey's script.
I've made the following experience:
float shadowOffset = 1.0f // for a UIBarButtonItem in UINavigationItem
float shadowOffset = 0.0f // for a UIBarButtonItem in UIToolBar
This was observed with iOS 6.1 SDK.
(Now obsolete under iOS 7)