iOS UITextField with gradien background - ios

I'd like to have a UITextField with a gradient background to make one of the options of my project a bit more visually appealing.
I'm trying to subclass UITextField class overriding initWithFrame, but it doesn't work. I've never tried to subclass a UIControl before so I guess I'm missing something.
Could somebody give me a hand? Thank you in advance!

This should work:
textView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"gradient.jpg"]];
But you will have to change the control to the TextView.

You can try this answer: iPhone UITextField background color
And add a gradient with CAGradientLayer

The UITextField has property background, which is of type UIImage. So you can either draw an UIImage at runtime or load a ready image and set it as background of your UITextField. This way you can achieve whatever look you like for your text field.

you are just near to it subclassing is best idea for it but instead of overriding initWithFrame just use as below code in your subclassed .m file
- (CGRect)textRectForBounds:(CGRect)bounds
{
return CGRectInset(bounds, 5, 0);
}
- (CGRect)editingRectForBounds:(CGRect)bounds
{
return CGRectInset(bounds, 5, 0);
}
- (void)drawRect:(CGRect)rect
{
UIImage *textFieldBackground = [[UIImage imageNamed:#"text_field_teal.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15.0, 5.0, 15.0, 5.0)];
[textFieldBackground drawInRect:[self bounds]];
}
as this works for me i think it will works for you
Happy Coding :)
Enjoy the Day !!

Related

IBDesignable UILabel setting text to NSLocalizedString in drawRect or willMoveToSuperview crashes Xcode

I am trying to retroactively localize an app by subclassing an IBDesignable to have a property like so:
#property IBInspectable NSString *localizedKey;
Then I thought I could easily override the proper function in the UILabel's lifecycle to do this:
if (self.localizedKey) self.text = NSLocalizedString(self.localizedKey, nil);
Here's an example of what I tried to do:
- (void) drawRect:(CGRect)rect {
NSLog(#"roundedlabel");
[super drawRect:rect];
[self.layer setCornerRadius:cornerRadius];
[self.layer setMasksToBounds:YES];
[self.layer setBorderWidth:borderWidth];
[self.layer setBorderColor:[borderColor CGColor]];
self.clipsToBounds = YES;
}
- (void) willMoveToSuperview:(UIView *)newSuperview {
[super willMoveToSuperview:newSuperview];
NSLog(#"roundedlabel");
if (self.localizedKey) self.text = NSLocalizedString(self.localizedKey, nil);
}
I also tried moving the if (self.localizedKey) to various locations in drawRect.
My plan was to then set up the Localizable.strings file manually with known localizedKeys assigned working through the XIB files. However, I am finding two things.
It seems as though the normal methods called in the life cycle
of a view are not being called for my IBDesignable UILabel subclass.
I have entered log statements into drawRect and
willMoveToSuperview, and these log statements never print out.
XCode almost always crashes & immediately closes when I try to open
a xib in Interface Builder that contains this subclassed label (so no error messages).
At run time, when I see a view that involves an affected xib, I don't see any sign of the localized string AND I don't see 'roundedlabel' printed anywhere in my log.
What's going on? In particular:
(1) How come these functions don't run at all for my subclassed IBDesignable UILabel subclass?
(2) Is there a way to do what I want to do?
I'd create an extension on UILabel and use runtime key values in the storyboard / XIB to set the localisation keys.
extension UILabel {
func setHBLocalisationKey(key: String) {
self.text = ...
}
}
or
#implementation UILabel (HBLocalisation)
- (void)setHBLocalisationKey:(NSString *)key {
self.text = NSLocalizedString(key, nil);
}
#end
This will now work on any label without requiring a custom subclass and it won't tamper with the Xcode UI which seems to be causing some issues with your current approach.

Customize Button shape in ios 7.1

Apple has added Button shape feature in ios 7.1. But I need to make it disable for my app or change its default color, shape to match UI of my app. It is possible without using custom type button? Please help me.
Sub class the button and try which shape you want....
#import "YourButton.h"
#import <QuartzCore/QuartzCore.h>
#implementation YourButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)awakeFromNib
{
[super awakeFromNib];
CALayer *mask = [CALayer layer];
mask.contents = (id)[[UIImage imageNamed:#"ge.png"] CGImage]; // ge is the black & white png image
CGSize size = self.frame.size;
mask.frame = CGRectMake(0, 0, size.width, size.height);
self.layer.mask = mask;
[self.layer setMasksToBounds:YES];
}
#end
For your reference sample is attached Here
These features reflect on apples default button control(may be nav bar).
You don't need to worry about,these features are not app specific but for all apps.
If you want to ignore, don't use default button, instead go with custom.
P.S. After editing question by OP:
You can't achieve this without using custom implementation.
For More:reference
Well you can make it custom type & use image according to the way you want to view that.
IF you use a UINavigationBar or UIToolbar as the of the button then you will get a slightly darker color of the bar's tint color.
Otherwise you can get an underline whats color matches the text color, so i think this should not bother you. Leave it as it is.

UIImageView image not retained during drawRect event in iOS7

I am transitioning an app project from iOS-6.1 and xcode4 to iOS-7 and xcode5. My original iOS-6.1 routine to draw on a transparent UIView above an UIImageView does not work in iOS7. Here is what I have done and how I have fixed it. I'm hoping someone can tell me how to do it better!
Using InterfaceBuilder, I create a square (320 x 320) UIImageView on my View Controller view. I then make a 320 x 320 UIView directly above it and use Interface Builder Attributes Inspector to make it transparent.
Then I link up the setters and getters in Interface Builder. The UIImageView #property is (nonatomic, retain). I then subclass the now-transparent UIView and do my drawing in drawRect.
In iOS6.1 this works just fine. In iOS-7 I have a problem.
(Several, actually). As a side note, in xcode5 I cannot get the Attributes Inspector to appear when I select the UIView, when I try to make the UIView transparent. Could this be a bug, perhaps in my installation of xcode5, or is the xcode5 Attributes Inspector no longer supporting UIViews?
So I make the UIView transparent programmatically in iOS-7. I'm doing it here in the UIView's drawRect, which is probably overkill, but I'm still trying to figure out what's going on:
self.backgroundColor = [UIColor clearColor];
self.opaque= NO;
self.window.backgroundColor = [UIColor clearColor];
and then I have to make the UIImageView appear, also in drawRect, using this code
UIImage *myImage = [UIImage imageNamed:#"myImage.png"];
CGRect imageRect;
imageRect.origin.x = self.bounds.origin.x + 10;
imageRect.origin.y = self.bounds.origin.y + 10;
imageRect.size.width = 300;
imageRect.size.height = 300;
[myImage drawInRect:imageRect];
And things are now fine. I get what I want which is my drawing on top of the image. But, it seems like a terrible performance hit to be calling myImage every time drawRect needs to be called.
Can anybody see why my original method of displaying the UIImageView once does not work in iOS-7? Has anybody a better solution to my expensive show-the-image-every-time method?
Thanks in advance
TFR

Achieving bright, vivid colors for an iOS 7 translucent UINavigationBar

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).

iPhone Custom UISlider preload and rounded edges issues

I'm trying to implement a custom UISlider, I've extended it with a class called UISliderCustom which has the following code:
#implementation UISliderCustom
- (id)initWithCoder:(NSCoder *)aDecoder{
if(self == [super initWithCoder:aDecoder]){
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, 200, 13);
UIImage *slideMin = [[UIImage imageNamed:#"slideMinimum.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
UIImage *slideMax = [[UIImage imageNamed:#"slideMaximum.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
[self setThumbImage:[UIImage imageNamed:#"slideThumb.png"] forState:UIControlStateNormal];
[self setThumbImage:[UIImage imageNamed:#"slideThumb.png"] forState:UIControlStateHighlighted];
[self setMinimumTrackImage:slideMin forState:UIControlStateNormal];
[self setMaximumTrackImage:slideMax forState:UIControlStateNormal];
}
return self;
}
#end
I ran into two small problems
When I slide over the slider to one of the edges (progress = 0.0 / progress = 1.0), I can clearly see "left overs" in the sides, im not sure how to handle that as well, unfortunately :)
Slider images:
Problem:
I see the regular UISlider (blue and silver) for a couple of seconds, and only then the custom graphics is loaded, or when i actually move the slider. I'm not sure why this is happening.. EDIT: This only happens in the simulator, works fine now.
Thanks in advance for any assistance :)
Shai.
You have no need to subclass UISlider to achieve this effect, and if you did you certainly wouldn't set the track images in the drawRect method. drawRect should contain drawing code only, it is called whenever any part of the control needs redrawing.
Set the thumb and track images in a separate method, either within your subclass (called from initWithFrame and initWithCoder) or in the object that creates the slider in the first place. This only needs to be done once, when the slider is first created. Don't override drawRect.
You don't need to call awakeFromNib manually either, unless you have some specific code in there as well? That would be a common place to set custom images in a subclass, if you only ever used the slider from IB.
For the square ends, the problem is that the extreme edge of your track image is square, so it is showing around the thumb. Make both ends of the track image rounded, with a 1px stretchable area in the middle, like this:
I just had a very similar problem myself. It turned out that the size (width x height) of the slider that I added in interface builder didn't match the sizes of the images I was using to customize the slider. Once I made them match, those "leftovers" at the ends of the slider went away.

Resources