Tiled Background Image: Can I do that easily with UIImageView? - iphone

I have a fullscreen background image that is tiled, i.e. it has to be reproduced a few times horizontally and vertically in order to make a big one. Like in the browsers on ugly home pages ;)
Is UIImageView my friend for this?

If I understand your question correctly you can use colorWithPatternImage: on UIColor then set the background color on a UIView.
If you must use a UIImageView you can do the same but whatever image you place in the image view will draw in front of the tiled image.

To get alpha to work with pattern image, make sure you have the following set:
view.backgroundColor = [UIColor colorWithPatternImage:aImage];
view.layer.opaque = NO;

In WWDC 2018 video session 219 - Image and Graphics Best Practices, Apple engineer explicitly recommends not to use the pattern color for tiling backgrounds:
I recommend not using patterned colors with a background color property on UIView. Instead, create a UIImageView. Assign your image to that image view. And use the functions on UIImageView to set your tiling parameters appropriately.
So the best and simplest way to create a tiled background would be like this:
imageView.image = image.resizableImage(withCapInsets: .zero, resizingMode: .tile)
Or even simpler, if you use asset catalog – select your pattern image asset and, in the Attributes inspector, enable Slicing (Horizontal/Vertical or both), set the insets to zero, and width/height to the dimensions of your image:
then simply assign this image to your image view (Interface Builder works, too), just don't forget to set the UIImageView's contentMode to .scaleToFill.

For years I used Bill Dudney's approach, but iOS 6 has a much better solution. And ... today I found a way to make this work on old versions of iOS too.
create the new class "UIImage+Tileable" (copy/paste source below)
import this in any class where you want a UIImageView with tileable image. It's a category, so it "upgrades" all your UIImage's into tileable ones, using standard Apple calls
when you want a "tiling" version of an image, call: "image = [image imageResizingModeTile]"
UIImage+Tileable.h
#import <UIKit/UIKit.h>
#interface UIImage (Tileable)
-(UIImage*) imageResizingModeTile;
#end
UIImage+Tileable.m
#import "UIImage+Tileable.h"
#implementation UIImage (Tileable)
-(UIImage*) imageResizingModeTile
{
float iOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if( iOSVersion >= 6.0f )
{
return [self resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode:UIImageResizingModeTile];
}
else
{
return [self resizableImageWithCapInsets:UIEdgeInsetsZero];
}
}
#end

I use a variation of #Rivera's solution:
Put the following in a UIView extension:
- (void)setColorPattern:(NSString *)imageName
{
[self setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:imageName]]];
}
Then you can set the background pattern in the storyboard/xib file:

As I really like Interface Builder I created this UIImageView subclass to apply tiled backgrounds:
#interface PETiledImageView : UIImageView
#end
#implementation PETiledImageView
- (void)awakeFromNib
{
[super awakeFromNib];
UIImage * imageToTile = self.image;
self.image = nil;
UIColor * tiledColor = [UIColor colorWithPatternImage:imageToTile];
self.backgroundColor = tiledColor;
}
#end
I tried overriding setImage: but it seems IB doesn't call it when decoding a Nib file.

Swift version of Daniel T's solution. You still need to set the keyPath value in IB. Of course you could be more careful unwrapping the Optional UIImage.
extension UIView {
var colorPattern:String {
get {
return "" // Not useful here.
}
set {
self.backgroundColor = UIColor(patternImage: UIImage(named:newValue)!)
}
}
}

Related

iOS 7 dynamic blur effect like in Control Center

I'm trying to make a controller that will be similar to Control Center in iOS7. From WWDC session #226 I've learnt how to get blurred image with different effects
UIGraphicsBeginImageContextWithOptions(image.size, NULL, 0);
[view drawViewHierarchyInRect:rect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lightImage = [newImage applyLightEffect];
So, in other words, we just capture some image (make screenshot), perform blur effect and use this blurred image for our needs.
But if you open control center above some dynamic content you'll notice that control center's blurred background is changing as well as content does.
Does anybody know how to replicate this behavior?
The only way I see it is to capture content and make blur effect with some interval (e.g. half a second). But it looks redundantly.
Here are ready solutions that I've found:
1. The most unexpected: Use UIToolBar
- (id) initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
[self setup];
}
return self;
}
- (id) initWithCoder:(NSCoder *)coder
{
if ((self = [super initWithCoder:coder]))
{
[self setup];
}
return self;
}
- (void) setup
{
if (iOS7OrLater)
{
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:self.bounds];
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
toolbar.barTintColor = self.tintColor;
[self insertSubview:toolbar atIndex:0];
}
}
UIToolbar can be used for this needs, bacuse it has his only build-in blur mechanism, and this mechanism is dynamic, what is good. But the bad thing is that in some reason it ignores colors and makes background looks irredeemably...
Update:
To avoid color breaking, do not use barTintColor. You also may change style of toolbar if you want dark styled blur (use UIBarStyleBlack).
2. FXBlurView.
Unlike toolbar it more positive, but it's dynamic mechanism is rare yet and in fact it can be used only for static background. (dynamic = NO).
In iOS8 we can implement blur effect on views using UIVisualEffect class.
You can use below code to apply blur effect on view.
UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView;
visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
visualEffectView.frame = MYview.bounds;
[MYview addSubview:visualEffectView];
I've found LiveFrost to be a great, and easy to integrate project for live blurring.
https://github.com/radi/LiveFrost/
You can use UIVisualEffect from storyboard.
Drag the Visual Effect With Blur on the storyboard. The desired effect can be achieved by setting alpha of the BACKGROUND COLOR. The subviews should be added to View of Visual Effect View and they are not affected by the background blur.
The Vibrancy effect must be selected in View options above.
See image:
Using navigation bar to provide blurring will not work on older devices running iOS 7. As they are running lighter version of iOS 7 with almost no t

Change font color of the label and UIImageview image across entire views of the application iOS

I'm trying to change the theme of the application(UILabel font color and images of UIImageview) based on the condition.
I'm checking one condition, if it is 0 entire label in the application should be in red color else it should be in blue color as well as UIImageview images.
2 sets of images are there. based on the condition i need to change the images also.
Anyone give me some ideas to start..
Thank you..
You could add a category for UILabel which should have the method
-(UIColor *)labelColor {
//depend on ur condition, return the color
}
In all the label declarations, set the font color as
lbl.textColor = [lbl labelColor];
Similarly for UIImageView.
Update:
Create a new file of type Cocoa-Touch Objective C category through Xcode.
You can name the file like UILabel+Color and the interface will be like
#interface UILabel (Color)
-(UIColor *)labelColor;
#end
In .m file, implement the method as stated at the top.
For more info on Categories, see this tutorial and Apple documentation
In all your viewcontroller's viewWillAppear method, iterate through the subviews and if view is of type UILabel then change textcolor. Similarly for UIImageView
for (UIView *child in view.subviews)
{
if([child isKindOfClass:[UILabel class]])
{
UILabel *lbl = (UILabel*)child;
lbl.textColor = [UIColor redColor];
}
}
I haven't tried, but think this should work.
Best way to do is, create a singleton class, where you will make/change properties of labels/images/buttons, any UI object.
You'll just have to access this class's methods for every UI object, and its done. No need to write multiple lines of code again and again.
:)

UIView shadow drawing wrong

Trying to draw a shadow using code from this question: How do I draw a shadow under a UIView?
I implement it in a UIView subclass as discussed, but when I try and use it using UIView *shadow = [[ShadowView alloc]initWithFrame:CGRectMake(100,100,100,100)]; I get only a black square, rather than something resembling shadow.
Am I missing something here?
I know this an ancient question, but I came across it via google as I was trying to do the same thing. So I thought I would post incase anyone else has the same problem. I finally discovered a fix after reading this tutorial: http://www.raywenderlich.com/2134/core-graphics-101-glossy-buttons
You need to either uncheck Opaque, and set the Background to Clear Color in IB.
OR as shown in the tutorial set them in initWithCoder
-(id) initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
Yup, you probably need to explicitly add an #import to the top of your class. I've had the same issue before and that fixed it. (Can't exactly explain why though)

drawRect not being called in my subclass of UIImageView

I have subclassed UIImageView and tried to override drawRect so I could draw on top of the image using Quartz 2D. I know this is a dumb newbie question, but I'm not seeing what I did wrong. Here's the interface:
#import <UIKit/UIKit.h>
#interface UIImageViewCustom : UIImageView {
}
- (void)drawRect:(CGRect)rect;
#end
And the implementation:
#import "UIImageViewCustom.h"
#implementation UIImageViewCustom
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
}
return self;
}
- (void)drawRect:(CGRect)rect {
// do stuff
}
- (void)dealloc {
[super dealloc];
}
#end
I set a breakpoint on drawRect and it never hits, leading me to think it never gets called at all. Isn't it supposed to be called when the view first loads? Have I incorrectly overridden it?
It'll only get called if the view is visible, and dirty. Maybe the problem is in the code that creates the view, or in your Nib, if that's how you're creating it?
You'll also sometimes see breakpoints failing to get set properly if you're trying to debug a "Release" build.
I somehow missed the first time that you're subclassing UIImageView. From the docs:
Special Considerations
The UIImageView class is optimized to
draw its images to the display.
UIImageView will not call drawRect: in a
subclass. If your subclass needs
custom drawing code, it is recommended
you use UIView as the base class.
So there you have it. Given how easy it is to draw an image into your view using [UIImage drawInRect:], or by using CALayer, there's probably no good reason to subclass UIImageView anyway.
Try to add
Edit:
- (id)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
[self setClearsContextBeforeDrawing:YES];//add this line also
}
return self;
}
- (void)setNeedsDisplay{
[self setNeedsDisplayInRect:self.frame];
}
into your code.
hope this helps.
Thanks,
madhup
Not directly answering your question, but may solve your problem:
Why do this with a subclass of UIImageView? Subclassing can always be problematic, especially for classes that aren't designed to be subclassed--and I bet UIImageView isn't. If you just want to draw stuff on top of an image, then create a view with a transparent background, draw whatever you want, and place it directly over the image.
Depending on your specific case, it could make sense to use a UIButton with a background image instead of a UIImageView. You could even set userInteractionEnabled to NO and the result would be indistinguishable from a UIImageView.
In this case your UIButton subclass would simply include:
- (void)drawRect:(CGRect)rect
{
if (kSomethingSpecial) {
[self setBackgroundImage:[UIImage imageNamed:#"RedBackground.png"]
forState:UIControlStateNormal];
}
}
Disclaimer - I would only recommend this if you have plans to use the image as a button at least some of the time. I can't wholeheartedly endorse using a UIButton as a workaround for this drawRect behaviour in UIImageView, as I'm sure Apple has its reasons for writing their API this way, like Mark referenced.

How to set background image of a view?

I am a beginner at Obj-C/Cocoa Touch/iPhone OS.
I wish to have a background for my app with different images everytime the the view is called.
Say I have 10 images. I 've used it like this:
//random image generation
NSString* imageName;
int aRandomNumber = arc4random() % 10;
imageName =[NSString stringWithFormat:#"g%d.jpg",aRandomNumber];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:imageName]]];
NSLog(#"aRandomNumber is %d", aRandomNumber);
//random image is generated
Its working fine
Now, say I have text labels on my view and the text isn't displaying correctly due to image colors.
How can I make it a little transparent? (I guess in Interface Builder its called alpha.)
Say my image isn't 320x480. How do I set it to fill the entire view?
How can I do it with UIView/UIImageView?
I found initWithHue:saturation:brightness:alpha: in the documentation but it's not working:
self.view.backgroundColor = [[UIColor alloc] initWithHue:0.0 saturation:1.0 brightness:1.0 alpha:1.0];
Please Help!
A friend suggested........
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:imageName]]];
..........he told it's more efficient because it doesn't save the image in the cache.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"imageName.png"]];
more info with example project
Besides all of the other responses here, I really don't think that using backgroundColor in this way is the proper way to do things. Personally, I would create a UIImageView and insert it into your view hierarchy. You can either insert it into your top view and push it all the way to the back with sendSubviewToBack: or you can make the UIImageView the parent view.
I wouldn't worry about things like how efficient each implementation is at this point because unless you actually see an issue, it really doesn't matter. Your first priority for now should be writing code that you can understand and can easily be changed. Creating a UIColor to use as your background image isn't the clearest method of doing this.
use this
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Default"]];
simple way :
-(void) viewDidLoad {
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"background.png"]];
[super viewDidLoad];
}
It's a very bad idea to directly display any text on an irregular and ever changing background. No matter what you do, some of the time the text will be hard to read.
The best design would be to have the labels on a constant background with the images changing behind that.
You can set the labels background color from clear to white and set the from alpha to 50.0 you get a nice translucent effect. The only problem is that the label's background is a stark rectangle.
To get a label with a background with rounded corners you can use a button with user interaction disabled but the user might mistake that for a button.
The best method would be to create image of the label background you want and then put that in an imageview and put the label with the default transparent background onto of that.
Plain UIViews do not have an image background. Instead, you should make a UIImageView your main view and then rotate the images though its image property. If you set the UIImageView's mode to "Scale to fit" it will scale any image to fit the bounds of the view.
You want the background color of your main view to be semi-transparent? There's nothing behind it... so nothing will really happen however:
If you want to modify the alpha of any view, use the alpha property:
UIView *someView = [[UIView alloc] init];
...
someView.alpha = 0.8f; //Sets the opacity to 80%
...
Views themselves have the alpha transparency, not just UIColor.
But since your problem is that you can't read text on top of the images... either:
[DESIGN] Reconsider the design/placement of the images. Are they necessary as background images? What about the placement of the labels?
[CODE] It's not exactly the best solution, but what you could do is create a UIView whose frame takes up the entire page and add some alpha transparency to it. This will create an "overlay" of sorts.
UIView *overlay = [[[UIView alloc] init] autorelease];
overlay.frame = self.view.bounds;
overlay.alpha = 0.2f;
[self.view addSubview:overlay];
... Add the rest of the views
You can set multiple background image in every view using custom method as below.
make plist for every theam with background image name and other color
#import <Foundation/Foundation.h>
#interface ThemeManager : NSObject
#property (nonatomic,strong) NSDictionary*styles;
+ (ThemeManager *)sharedManager;
-(void)selectTheme;
#end
#import "ThemeManager.h"
#implementation ThemeManager
#synthesize styles;
+ (ThemeManager *)sharedManager
{
static ThemeManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[ThemeManager alloc] init];
}
[sharedManager selectTheme];
return sharedManager;
}
- (id)init
{
if ((self = [super init]))
{
}
return self;
}
-(void)selectTheme{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *themeName = [defaults objectForKey:#"AppTheme"] ?: #"DefaultTheam";
NSString *path = [[NSBundle mainBundle] pathForResource:themeName ofType:#"plist"];
self.styles = [NSDictionary dictionaryWithContentsOfFile:path];
}
#end
Can use this via
NSDictionary *styles = [ThemeManager sharedManager].styles;
NSString *imageName = [styles objectForKey:#"backgroundImage"];
[imgViewBackGround setImage:[UIImage imageNamed:imageName]];