I am using JSQMessageViewController and I am facing the issue (only in ios14) that i cant see media items like Images, Video and Audio in device though these views are generating debug view hierarchy. See below attached image:-
debug view hierarchy screenshot:
here is the description of UIImage inside collection view cell:
<UIImageView: 0x7fe7d6d95b30; frame = (20 8; 177 131); clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x600001ce4ec0>>
here is the screenshot attached of screen:
You can see the view has generated space for image, but its not showing up!
Is anyone facing this issue? how can i solve this problem. This issue is occurring in iOS 14, it works perfectly in iOS 13.
You need to overwrite in JSQMessagesMediaViewBubbleImageMasker.m
method - (void)jsq_maskView:(UIView *)view withImage:(UIImage *)image and change line:
view.layer.mask = imageViewMask.layer;
to be
view.maskView = imageViewMask;
I suggest you to use category for that. For me that was solution.
I would like to suggest to change like as follows along with the Vladimir answer for backward compatibility:
if (#available(iOS 14.0, *)) {
view.maskView = imageViewMask;
} else {
view.layer.mask = imageViewMask.layer;
}
I can't figure out how to change my AdMob banner's background color when the ad doesn't fit. Is this possible? The code below wouldn't work for me.
self.ad.backgroundColor= [UIColor whiteColor];
This is actually achieved through AdMob's dashboard.
Go to AdMob.com
Select Monetize on the top toolbar
Select the application on the left side bar that you want to change the background color for
Select the Ad Unit of the banner
In the Text ad style drop down menu select Customized
Select Background color and change it to whichever color you desire
Select Save and you're all done
It may take a few minutes for changes to appear in your application.
You could add your GADBannerView to another UIView that you set the backgroundColor of. This would require using AdMob's default sizes to make sure that image banners fit properly. The down fall of this is that text based ads will be restricted to this size also instead of filling the entire ad area.
For example:
#import "ViewController.h"
#import GoogleMobileAds;
#define ADUNIT_ID #"yourAdUnitID"
#interface ViewController () <GADBannerViewDelegate> {
GADBannerView *admobBanner;
UIView *backgroundView;
}
#end
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
// Create our AdMob banner
admobBanner = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];
admobBanner.adUnitID = ADUNIT_ID;
admobBanner.rootViewController = self;
admobBanner.delegate = self;
[admobBanner loadRequest:[GADRequest request]];
// Create a view to put our AdMob banner in
backgroundView = [[UIView alloc]initWithFrame:CGRectMake(0,
self.view.frame.size.height - admobBanner.frame.size.height,
self.view.frame.size.width,
admobBanner.frame.size.height)];
// Hide view until we have an ad
backgroundView.alpha = 0.0;
// Set to color you require
backgroundView.backgroundColor = [UIColor redColor];
// Add our views
[self.view addSubview:backgroundView];
[backgroundView addSubview:admobBanner];
// Center our AdMob banner in our view
admobBanner.center = [backgroundView convertPoint:backgroundView.center fromView:backgroundView.superview];
}
-(void)adViewDidReceiveAd:(GADBannerView *)adView {
NSLog(#"adViewDidReceiveAd");
[UIView animateWithDuration:0.5 animations:^{
backgroundView.alpha = 1.0;
}];
}
-(void)adView:(GADBannerView *)adView didFailToReceiveAdWithError:(GADRequestError *)error {
NSLog(#"adView:didFailToReceiveAdWithError: %#", [error localizedDescription]);
[UIView animateWithDuration:0.5 animations:^{
backgroundView.alpha = 0.0;
}];
}
iPhone / iPad
You should insert the ad in a container view.
Then, in the delegate that is called when the ad is loaded adjust the container width to be the same size as the ad view
You need to start by figuring out what views compose the ad view. Probably you are changing the view's color, but it has another view on top of it that contains the ad, and total blocks the parent view.
Start by placing a breakpoint in your code (I often place it in -viewDidAppear:) and once in there, type this in the debugger to see the subviews of the ad view:
po self.ad.subviews
My guess is that you'll see one subview that stretches the full length of the main window. It may even be a UIImageView that contains the ad image. But you can continue to look at the subviews of the subviews, either in the debugger or by adding code in -viewDidAppear:.
This is probably view you want to mess with. In -viewDidAppear:, try adding code to color the subview's background instead:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView *adSubview = self.ad.subviews.firstObject;
adSubview.backgroundColor = [UIColor whiteColor];
}
This code should be safe even if the ad or its subviews property returns nil.
I think you should fill rect of UIView same Admob size.
bannerView = GADBannerView(frame: rectBanner)
bannerView.adUnitID = "xxxxxxxxxxxxxxxxxx"
bannerView.rootViewController = self
frame size(rectBanner) should be match with Admob Size.
Can I have some UIView which will always appear on top in iOS?
There are lots of addSubview in my project but I need to have one small view which will always appear. SO is there any other option than
[self.view bringSubViewToFront:myView];
Thanks
One more option (especially if you want to overlap several screens, with logo for example) - separate UIWindow. Use windowLevel to set the level of new window.
UILabel *devLabel = [UILabel new];
devLabel.text = #" DEV ";
devLabel.font = [UIFont systemFontOfSize:10];
devLabel.textColor = [UIColor grayColor];
[devLabel sizeToFit];
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
static UIWindow *notificationWindow;
notificationWindow = [[UIWindow alloc] initWithFrame:
CGRectMake(screenSize.width - devLabel.width, screenSize.height - devLabel.height,
devLabel.width, devLabel.height)];
notificationWindow.backgroundColor = [UIColor clearColor];
notificationWindow.userInteractionEnabled = NO;
notificationWindow.windowLevel = UIWindowLevelStatusBar;
notificationWindow.rootViewController = [UIViewController new];
[notificationWindow.rootViewController.view addSubview:devLabel];
notificationWindow.hidden = NO;
Another option is set layer.zPosition of your UIView.
You need to add
#import <QuartzCore/QuartzCore.h>
Framework to your .m file.
And set such like
myCustomView.layer.zPosition = 101;// set maximum value as per your requirement.
For more information about layer.zPosition read this documentation.
Discussion
The default value of this property is 0. Changing the value of this property changes the the front-to-back ordering of layers onscreen. This can affect the visibility of layers whose frame rectangles overlap.
The other option is to add other subviews below this always-on-top subview. For example:
[self.view insertSubview:subview belowSubview:_topSubview];
There's no solution with Interface Builder if you search for this kind. It should be done programmatically. If you don't want to use bringSubviewToFront: everytime, just insert other subviews below this one.
Many times your view did not appear in viewDidLoad or, if your view comes from parentViewController (for example in many transitions like modal segue..) your can see parentViewController only in viewDidAppear so:
Try to put bringSubviewToFront in :
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.view bringSubViewToFront:myView];
// or if your view is attached in parentViewController
[self.parentViewController.view bringSubViewToFront:myView];
}
Good luck!
iOS 7.1 UPDATE: Looks like the workaround for modifying the alpha channel in the UINavigationBar has been ignored in this update. Right now, the best solution seems to be to just 'deal with it' and hope that whatever color you choose can render a translucent effect. I am still looking into ways of getting around this.
iOS 7.0.3 UPDATE: The GitHub library we created has been updated to slightly work around this issue when using iOS 7.0.3. Unfortunately, there is no magic formula to support both colors created in iOS 7.0.2 and earlier and iOS 7.0.3. Seems like Apple improved the saturation, but at the cost of opacity (since the blurred translucency is dependant on the opacity level). I, along with a few others, are working on creating a much better fix for this.
I'm sure many people have already come across the problem where iOS 7 tends to desaturate the color of a UINavigationBar that is translucent.
My goal is to achieve a UINavigationBar with this tint color, but translucent:
However, with translucency, I'm getting this. The background view is white, which I understand will make this view a bit lighter:
Is there any way to achieve the original color while still having translucency? I've noticed Facebook has been able to get their bar to be their rich, blue color, as displayed here:
..so I know there has to be some way. Background views obviously make a difference here, but most of their content is also gray/white. It seems that regardless of whatever bar tint color you put in, you are unable to get vivid colors under translucency.
Updated with solution.
Here's the solution that I ended up coming up with. I took aprato's solution and then encompassed the custom UINavigationBar within a UINavigationController subclass. I have created a repository that has this implementation listed below, along with an example app.
////////////////////////////
// CRNavigationBar.m
////////////////////////////
#import "CRNavigationBar.h"
#interface CRNavigationBar ()
#property (nonatomic, strong) CALayer *colorLayer;
#end
#implementation CRNavigationBar
static CGFloat const kDefaultColorLayerOpacity = 0.5f;
static CGFloat const kSpaceToCoverStatusBars = 20.0f;
- (void)setBarTintColor:(UIColor *)barTintColor {
[super setBarTintColor:barTintColor];
if (self.colorLayer == nil) {
self.colorLayer = [CALayer layer];
self.colorLayer.opacity = kDefaultColorLayerOpacity;
[self.layer addSublayer:self.colorLayer];
}
self.colorLayer.backgroundColor = barTintColor.CGColor;
}
- (void)layoutSubviews {
[super layoutSubviews];
if (self.colorLayer != nil) {
self.colorLayer.frame = CGRectMake(0, 0 - kSpaceToCoverStatusBars, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + kSpaceToCoverStatusBars);
[self.layer insertSublayer:self.colorLayer atIndex:1];
}
}
#end
////////////////////////////
// CRNavigationController.m
////////////////////////////
#import "CRNavigationController.h"
#import "CRNavigationBar.h"
#interface CRNavigationController ()
#end
#implementation CRNavigationController
- (id)init {
self = [super initWithNavigationBarClass:[CRNavigationBar class] toolbarClass:nil];
if(self) {
// Custom initialization here, if needed.
}
return self;
}
- (id)initWithRootViewController:(UIViewController *)rootViewController {
self = [super initWithNavigationBarClass:[CRNavigationBar class] toolbarClass:nil];
if(self) {
self.viewControllers = #[rootViewController];
}
return self;
}
#end
iOS 7.0.3 UPDATE: As you see above 7.0.3 changed things. I've updated my gist. Hopefully this will just go away as people upgrade.
Original Answer:
I ended up with a hack combining the two of the other answers. I'm subclassing UINavigationBar and adding a layer to the back with some extra space to cover if any of the various height status bars are up. The layer gets adjusted in layout subviews and the color changes whenever you set barTintColor.
Gist: https://gist.github.com/aprato/6631390
setBarTintColor
[super setBarTintColor:barTintColor];
if (self.extraColorLayer == nil) {
self.extraColorLayer = [CALayer layer];
self.extraColorLayer.opacity = self.extraColorLayerOpacity;
[self.layer addSublayer:self.extraColorLayer];
}
self.extraColorLayer.backgroundColor = barTintColor.CGColor;
layoutSubviews
[super layoutSubviews];
if (self.extraColorLayer != nil) {
[self.extraColorLayer removeFromSuperlayer];
self.extraColorLayer.opacity = self.extraColorLayerOpacity;
[self.layer insertSublayer:self.extraColorLayer atIndex:1];
CGFloat spaceAboveBar = self.frame.origin.y;
self.extraColorLayer.frame = CGRectMake(0, 0 - spaceAboveBar, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + spaceAboveBar);
}
The behavior of tintColor for bars has changed on iOS 7.0. It no longer affects the bar's background and behaves as described for the tintColor property added to UIView. To tint the bar's background, please use -barTintColor.You can use following code to make the app work with both ios6 and ios7.
if(IS_IOS7)
{
self.navigationController.navigationBar.barTintColor = [UIColor blackColor];
self.navigationController.navigationBar.translucent = NO;
}
else
{
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
}
IS_IOS7 is a macro which is defined in pch file as follows.
#define IS_IOS7 ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
I didn't come up with this solution but it seems to work fairly well. I just added it to viewDidLoad on my subclass of UINavigationController.
Source: https://gist.github.com/alanzeino/6619253
// cheers to #stroughtonsmith for helping out with this one
UIColor *barColour = [UIColor colorWithRed:0.13f green:0.14f blue:0.15f alpha:1.00f];
UIView *colourView = [[UIView alloc] initWithFrame:CGRectMake(0.f, -20.f, 320.f, 64.f)];
colourView.opaque = NO;
colourView.alpha = .7f;
colourView.backgroundColor = barColour;
self.navigationBar.barTintColor = barColour;
[self.navigationBar.layer insertSublayer:colourView.layer atIndex:1];
One low-fi way would probably be pinning a UIView that is the height of the Navigation Bar to the top of the view behind the bar. Make that view the same color as the navigation bar but play with the alpha until you get the desired effects:
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.navigationController.navigationBar.frame), 64)];
backgroundView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:1 alpha:.5];
[self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];
UIView behind
(Changed color from lower examples to emphasis transparency. Transparency/blurring is more noticeable when in movement.)
Subclassing the UINavigationBar and placing that same view above the background but behind everything else will probably achieve similar results while being less hacky.
Another solution I've seen tossed around is playing with the alpha of the UINavigationBar:
self.navigationController.navigationBar.alpha = 0.5f;
Edit: Actually, after testing it seems like this doesn't provide the intend behavior (or any behavior):
.8 alpha
Unadjusted alpha
Obviously, you will only want to do this on iOS 7 devices. So, add some version check before you implement any of these.
Instead of creating your UIColor object in the RGB format, use HSB and increase the saturation parameter. (Credits to Sam Soffes who describes this method here)
navigationBar.barTintColor = [UIColor colorWithHue:0.555f saturation:1.f brightness:0.855f alpha:1.f];
Note: This solution is a tradeoff and doesn't work well for colors with high saturation.
To pick the HSB color from your design you can use a tool like ColorSnapper which allows you to simply copy the UIColor HSB format.
You can also try the UIColor Category (GitHub Link) from David Keegan to modify existing colors.
The problem has now been fixed by Apple in the new 7.0.3 release.
I used #aprato's solution but found a few corner cases where the new layers from new VCs (eg. UINavigationItemButtonViews, UINavigationItemViews, etc) would be automatically inserted into a position below the extraColorLayer (which would cause those title or button elements to be affected by the extraColorLayer and thus fainter in color than they normally would be). So I adjusted #aprato's solution to force the extraColorLayer to stay at the index position 1. At index position 1, the extraColorLayer stays right above the _UINavigationBarBackground, but underneath everything else.
Here's my class implementation:
- (void)setBarTintColor:(UIColor *)barTintColor
{
[super setBarTintColor:barTintColor];
if (self.extraColorLayer == nil)
{
self.extraColorLayer = [CALayer layer];
self.extraColorLayer.opacity = kDefaultColorLayerOpacity;
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
self.extraColorLayer.backgroundColor = barTintColor.CGColor;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.extraColorLayer != nil)
{
self.extraColorLayer.frame = CGRectMake(0, 0 - kSpaceToCoverStatusBars, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + kSpaceToCoverStatusBars);
}
}
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview
{
[super insertSubview:view aboveSubview:siblingSubview];
[self.extraColorLayer removeFromSuperlayer];
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index
{
[super insertSubview:view atIndex:index];
[self.extraColorLayer removeFromSuperlayer];
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview
{
[super insertSubview:view belowSubview:siblingSubview];
[self.extraColorLayer removeFromSuperlayer];
[self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear
}
I've improved your code in my fork: https://github.com/allenhsu/CRNavigationController
With my modification, the result color on screen (picked on white background) will be exactly the same value passed into setBarTintColor. I think it's an amazing solution.
None of these hacks are required :). Simply set:
self.navigationController.navigationBar.translucent = NO;
For iOS 7, the default translucency has been kept to TRUE.
On a related note, you can set your title text color (with shadow) easily via:
NSShadow *titleShadow = [[NSShadow alloc] init];
titleShadow.shadowOffset = CGSizeMake(0.0f, -1.0f);
titleShadow.shadowColor = [UIColor blackColor];
NSDictionary *navbarTitleTextAttributes = #{NSForegroundColorAttributeName: [UIColor whiteColor],
NSShadowAttributeName: titleShadow};
[[UINavigationBar appearance] setTitleTextAttributes:navbarTitleTextAttributes];
I came across this Q/A while trying to setup an uniformly colored navigation bar with transparency DISABLED on iOS 7.
After experimenting a while with barTintColor I figured out that a very easy way of having an opaque navigation bar is to make a single pixel image of the desired color, make a stretchable image out of it, and setting it to the backgroundImage of the navigation bar.
UIImage *singlePixelImage = [UIImage imageNamed:#"singlePixel.png"];
UIImage *resizableImage = [singlePixelImage resizableImageWithCapInsets:UIEdgeInsetsZero];
[navigationBar setBackgroundImage:resizableImage forBarMetrics:UIBarMetricsDefault];
Three lines of code, very simple and works BOTH on iOS 6 and iOS 7 (barTintColor is unsupported on iOS 6).
Theres a great Dropin UINavigationController replacement available from Simon Booth available at GitHub Here GitHub - C360NavigationBar
If you're backward supporting iOS6 do a check on the root view controller as such:
PatientListTableViewController *frontViewController = [[PatientListTableViewController alloc] init];
UINavigationController *navViewController = [[UINavigationController alloc] initWithNavigationBarClass:[C360NavigationBar class] toolbarClass:nil];
if ([navViewController.view respondsToSelector:#selector(setTintColor:)]) {
//iOS7
[navViewController.view setTintColor:self.navBarTintColor];
[[C360NavigationBar appearance] setItemTintColor:self.navBarItemTintColor];
} else {
//iOS6
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
navViewController.navigationBar.tintColor = self.navBarTintColor;
}
[navViewController pushViewController:frontViewController animated:NO];
self.window.rootViewController = navViewController;
As #bernhard mentioned above it's possible to saturate the bar tint color to get desired navigation bar appearance.
I wrote an BarTintColorOptimizer utility for that kind of adjustment. It optimizes translucent bar tint color to make the bar's actual color match the desired color in iOS 7.x and later. Look at this answer for details.
Frankly speaking, above answers might be right but following trick worked for me with very ease.
// this is complete 100% transparent image
self.imageBlack = [[UIImage imageNamed:#"0102_BlackNavBG"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)
resizingMode:UIImageResizingModeStretch];
// this is non-transparent but iOS7
// will by default make it transparent (if translucent is set to YES)
self.imageRed = [[UIImage imageNamed:#"0102_RedNavBG"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2)
resizingMode:UIImageResizingModeStretch];
// some navigation controller
[nvCtrLeft.navigationBar setBackgroundImage:self.imageRed
forBarMetrics:UIBarMetricsDefault];
// some another navigation controller
[nvCtrCenter.navigationBar setBackgroundImage:self.imageRed
forBarMetrics:UIBarMetricsDefault];
Here are the images used for self.imageRed and self.imageBlack.
< > black image is in this brackets won't be visible as it is transparent :)
< > red image is in this brackets.
is there a way to use #aprato solution without subclassing UINavigationBar.
In my project my main view is a UIViewController.
the problem is that the navigationController is a readonly property, is there a way to use you class with my project because i can't use : [[UINavigationController alloc] initWithNavigationBarClass:
thanks
An easy way to get the color you want is using
[<NAVIGATION_BAR> setBackgroundImage:<UIIMAGE> forBarPosition:<UIBARPOSITION> barMetrics:<UIBARMETRICS>];
As long as your image has some alpha, the translucency will work and you can set the alpha by changing the image. This was just added in iOS7. The width and height for the image are 640x88px for vertical (add 20 to the 88 if you want it to be underneath the status bar).
I'm running into a tricky glitch.
I've got a .xib, which was created by XCode when I created a new UIViewController subclass. It has quite a few elements, including some UIButtons, a bunch of UILabels, a small UIView with some other views inside it, and a UIImageView containing a mostly-transparent image.
In viewDidLoad, I set the background color of the UIImageView to a color using a pattern image.
When I display this view controller in the simulator or on my iPhone 4 (both running iOS 5.1), everything goes smoothly; the patterned background displays, all the interactions work, and so on.
When I test on iOS 4.3, however (either in the simulator or on my iPod Touch 2G), it appears that everything I'm trying to manipulate based on an outlet (e.g. [self.myBackgroundImageView setBackgroundColor...] or [self.mySegmentedControl setEnabled:NO]) just doesn't work at all.
The only even vaguely unusual thing I'm doing when the view gets presented is this, which makes it size properly in a popover:
- (void) viewWillAppear:(BOOL)animated {
CGSize size = CGSizeMake(320, 480); // size of view in popover
self.contentSizeForViewInPopover = size;
[super viewWillAppear:animated];
}
I really can't think of anything else that might be the problem. I've cleaned, rebuilt, all that stuff. Still no dice.
Has anyone else encountered this?
UPDATE per request by ott:
Added the following at the end of -viewDidLoad:
NSLog(#"self.myBackgroundImageView = %# | %#", [self.myBackgroundImageView description], [[self.myBackgroundImageView backgroundColor] description]);
...The output is:
self.myBackgroundImageView = <UIImageView: 0x6d48c80; frame = (0 0; 320 480); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x6d48b60>> | <UIImageView: 0x5f459b0; frame = (0 0; 320 480); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x5f45890>> // kCGColorSpaceModelPattern 1
So... not nil. Not sure what the story is here.
UPDATE 2:
It appears the disabling of a UISegmentedControl in iOS 4.3 doesn't dim its display, so that's what that part was about. As for the background pattern image: I can't find confirmation of this, but I'm starting to think it's a bug in iOS 4 that makes a background color using a pattern-image UIColor not display properly on a UIImageView. It works fine if I make the UIImageView have a clear background and put the pattern image UIColor as the background of the main view instead. If anyone comes up with a workaround, or confirmation that this is indeed an iOS 4 bug, it would be much appreciated.