Customize uiswitch image properly? - ios

I have an UISwitch in my iOS 6 app, that's on and off image is customised.
self.testSwitch.onImage = [UIImage imageNamed:#"on"];
self.testSwitch.offImage = [UIImage imageNamed:#"off"];
I use 77 points wide and 22 points tall image for this purpose (154x44 in retina), as it is stated in the documentation. But my image does not fit to my uiswitch, it seems ugly, the default style hides my one, like on the attached image.
What should I set to make it work in a proper way?

Here is code from my book. This is not exactly what you want to do, but it shows the technique and will get you started! Notice that I'm using 79 by 27 (not sure where you got your numbers from):
UIGraphicsBeginImageContextWithOptions(CGSizeMake(79,27), NO, 0);
[[UIColor blackColor] setFill];
UIBezierPath* p = [UIBezierPath bezierPathWithRect:CGRectMake(0,0,79,27)];
[p fill];
NSMutableParagraphStyle* para = [NSMutableParagraphStyle new];
para.alignment = NSTextAlignmentCenter;
NSAttributedString* att =
[[NSAttributedString alloc] initWithString:#"YES" attributes:
#{
NSFontAttributeName:[UIFont fontWithName:#"GillSans-Bold" size:16],
NSForegroundColorAttributeName:[UIColor whiteColor],
NSParagraphStyleAttributeName:para
}];
[att drawInRect:CGRectMake(0,5,79,22)];
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.sw2.onImage = im;
Looks like this:

Apple doesn't have an Appearance API for UISwitch. You can set a tint color property (onTintColor). But that's not what you want, I guess. The problem about customizing UISwitch is that there's the opportunity that Apple will reject your app.
But there are some APIs for a custom switch such as RCSwitch(https://github.com/robertchin/rcswitch) or TTSwitch. A good tutorial and example of how to use RCSwitch can be found here: http://www.raywenderlich.com/23424/photoshop-for-developers-creating-a-custom-uiswitch.

Related

Set CALayer as SCNMaterial's diffuse contents

I've been searching all over the internet over the past couple of days to no avail. Unfortunately, the apple documentation about this specific issue is vague and no sample code is available (at least thats what I found out). What seems to be the issue you may ask...
I'm trying to set a uiview's layer as the contents of the material that is used to render an iPhone model's screen (Yep, trippy :P ). The iPhone's screen's UV mapping is set from 0 to 1 so that no issue persists in mapping the texture/layer onto the texels.
So, instead of getting this layer to appear rendered on the iPhone, same as left image, Instead, I get this rendered onto the iPhone like right image
Correct Render                                        Incorrect Render
Also note, that when I set a breakpoint and debug the actual iPhone node and view it in Xcode, a completely different render is shown and the layer gets half-fixed when I continue execution:
Now then... HOW do I fix this issue??? I've tried playing with the diffuse's contents transform matrix but nothing gets fixed. I've also tried resizing the UIView to 256x256 (since the UV seems to be 256x256 as shown in blender - the 3d modelling package), but that doesn't fix anything.
Here is the code for the layer:
UIView *screen = [[UIView alloc] initWithFrame:self.view.bounds];
screen.backgroundColor = [UIColor redColor];
UIView *temp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screen.bounds.size.width, 60)];
temp.backgroundColor = [UIColor colorWithRed:0 green:(112.f/255.f) blue:(235.f/255.f) alpha:1];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectInset(temp.bounds, 40, 0)];
label.frame = CGRectOffset(label.frame, 40, 0);
label.textColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
label.text = #"Select Track";
label.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:30];
label.minimumScaleFactor = 0.001;
label.adjustsFontSizeToFitWidth = YES;
label.lineBreakMode = NSLineBreakByClipping;
[temp addSubview:label];
UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(0, temp.bounds.size.height - 2, temp.bounds.size.width, 2)];
separator.backgroundColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
[temp addSubview:separator];
[screen addSubview:temp];
screen.layer.contentsGravity = kCAGravityCenter;
Edit
What's even weirder is that if I capture a UIImage of the view using:
- (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
and use that as the diffuse's content... everything works out perfectly fine?! It's really weird and frustrating since the image's size is exactly the same as the uiview's...
Edit 2
I ended up just using an image of the view as the texture, which makes things much more static than I needed. I won't set this as the answer because I'll still be waiting for a correct fix to this issue even if it in a long time. So, if you have an answer and this topic has been opened for a long time, please bump it if you can. The documentation on this section is just so poor.
New post on an old thread, but this day-in-age, it's possible to set the UIView itself as SCNMaterialProperty (diffuse) contents. Intention to support this feature is communicated directly from SceneKit engineering at Apple, though the documentation has not yet been updated to reflect it.
To tied back to the original post, do not set a UIView.layer as material property contents; instead set contents to the UIView itself.
[Update: according to Lance's comment below, support for views may be getting worse rather than getting better.]
The SceneKit docs pretty strongly suggest that, while there are cases where you can use animated CALayers as material content, that doesn't include UIView layers:
SceneKit cannot use a layer that is already being displayed elsewhere (for example, the backing layer of a UIView object).
That suggests that if you want to make animated content for your material, you're better off with either Core Animation used entirely on its own or SpriteKit.

UISearchBar set translucent to NO doesn't work

(I know this may seem as duplicate, but I'm telling you all nothing I've found here worked)
I have a UITableView with a search display controller and a search bar int it, I'm trying to set the tintColor according to the company colors. But it's translucent no matter what I try.
Here is the sample code:
[self.searchDisplayController.searchBar setTranslucent:NO];
[self.searchDisplayController.searchBar setBarTintColor:[[ConfToolbox sharedInstance] getBarTintColor]];
[[ConfToolbox sharedInstance] getBarTintColor] returns a dark-ish blue UIColor .
I've looked around for an answer but nothing worked, even this accepted answer.
Any help would be great.
Cheers,
Ayu.
I achieved what I wanted using this, just in case someone faces the same problem:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(10,10), YES, 0);
CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [[ConfToolbox sharedInstance] barTintColor].CGColor);
CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0,0,10,10));
UIImage* coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.searchDisplayController.searchBar setBackgroundImage:coloredImage forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
You can set the second parameter of CGContextSetFillColorWithColor with whatever color you want.
From the documentation
The default value is YES. If the search bar has a custom background
image, the default is YES if any pixel of the image has an alpha value
of less than 1.0, and NO otherwise.
Since the image is made from a color with an alpha value of 1, the translucent effect is off as stated.
try like this,
self.searchBar.frame = CGRectMake(self.searchBar.frame.origin.x, self.searchBar.frame.origin.y+7, self.searchBar.frame.size.width, 30);
self.searchBar.placeholder = #"Search...";
self.searchBar.layer.cornerRadius = 15;
self.searchBar.layer.backgroundColor = [UIColor redColor].CGColor;
self.searchBar.layer.borderWidth=8;
[[NSClassFromString(#"UISearchBarTextField") appearanceWhenContainedIn:[UISearchBar class], nil] setBorderStyle:UITextBorderStyleNone];
self.searchBar.layer.borderColor=[UIColor redColor].CGColor;

How should I use UIButtons with the iOS 6 style in iOS 7?

I'm making an app designed for iOS 6 and 7, and I want to allow users to choose which style they want: iOS 6 or iOS 7. Or at least just make it have the iOS 6 style completely. The app needs to be acceptable on the App Store.
I'm considering trying to find iOS 6 button images to use, but since I'm new to iOS GUI programming, I'm wondering if there is a cleaner way to do this that I don't know about. Is there a framework I could simply add so that I can use something like "[[UIButton6 alloc] init]" etc to make buttons with the older style? Or could I easily do this myself with rendering settings?
Any other approaches would also be helpful. Also, answers saying that this isn't possible at all are fine, but please no answers telling me that I should just use the iOS 7 GUI. I'm asking "how/can" I do this, not "should" I do this.
What I do is to add the drawing of an oval shape with a gradient background, myself. For example, here's code from one of my apps:
CAGradientLayer* grad = [CAGradientLayer new];
grad.frame = CGRectMake(0,0,15,15);
grad.colors = #[(id)[UIColor colorWithRed:1 green:1 blue:0 alpha:0.8].CGColor,
(id)[UIColor colorWithRed:.7 green:.7 blue:.3 alpha:0.8].CGColor];
UIGraphicsBeginImageContextWithOptions(CGSizeMake(15,15), NO, 0);
UIBezierPath* p = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0,0,15,15) cornerRadius:8];
[p addClip];
[grad renderInContext:UIGraphicsGetCurrentContext()];
[[UIColor blackColor] setStroke];
p.lineWidth = 2;
[p stroke];
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
im = [im resizableImageWithCapInsets:UIEdgeInsetsMake(7,7,7,7) resizingMode:UIImageResizingModeStretch];
Now use im as the background image of the button.
That code is just a "serving suggestion"; try it and then change the gradient colors or get rid of the gradient or whatever you feel like doing.
RED FLAG:
If you want to be accepted on the App Store, then intentionally targeting the iOS 6 look and feel is a serious danger.
As of February 1st, Apple is expecting all applications to be "optimized for iOS 7", which doesn't immediately exclude what you're discussing, but I wouldn't risk it personally.
Matt's answer is good, but I found a way to do this without rendering an image. Might be faster, and the code is more compact. I also like it a lot better when the gradient has 3 stops:
CAGradientLayer* grad = [CAGradientLayer new];
grad.frame = CGRectMake(0,0,button.frame.size.width,button.frame.size.height);
grad.colors = #[(id)[UIColor colorWithWhite:1 alpha:1].CGColor,(id)[UIColor colorWithWhite:.95 alpha:1].CGColor,(id)[UIColor colorWithWhite:1 alpha:1].CGColor];
grad.locations = #[#(0), #(.5), #(1)];
grad.cornerRadius = 10;
grad.borderColor = [UIColor blackColor].CGColor;
grad.borderWidth = .2;
[button.layer insertSublayer: grad atIndex:0]; //button is the UIButton you want to modify
Of course, edit the gradients, border, etc as needed. Here's what it looks like:
P.S. In case anyone "ninja'd" me, I originally said in this post that matt's answer doesn't allow you to set the gradient stops, but I was wrong.

CustomBadge rendering "grabage" around badge

I am using the CustomBadge library discussed in this question: How can I add a badge to a standard UIButton?
Here is my code:
CustomBadge* customBadge =
[CustomBadge customBadgeWithString:#"$2.99"
withStringColor:[UIColor whiteColor]
withInsetColor:[UIColor redColor]
withBadgeFrame:YES
withBadgeFrameColor:[UIColor whiteColor]
withScale:1.0
withShining:NO];
customBadge.frame = CGRectMake(self.btnUpgrade.frame.size.width - customBadge.frame.size.width + 15, -15, customBadge.frame.size.width, customBadge.frame.size.height);
[self.btnUpgrade addSubview:customBadge];
I get what I'm expecting:
I am using a NavigationController. When I segue into another ViewController and come back, my badge gets a "tail":
If I get rid of the customBadge.frame line, the badge renders correctly (at the wrong position though).
The code is executing on viewWillAppear:
Any clue what might be causing this?
The CustomBadge code is at: https://github.com/ckteebe/CustomBadge/blob/master/Classes/CustomBadge.m
I guess the problem is with paths. So, to resolve it I would:
Check that you start path from the point you want and not from a random one. That means you need to call CGContextMoveToPoint before calling CGContextBeginPath
Close (CGContextClosePath) each path before using it.
It looks like CustomBadge's drawRect uses a rect of a different size when I change the customBadge's frame in my code above. Maybe it has to do with clipToBounds vs maskToBounds.
I added this quick fix:
CustomBadge* customBadge =
[CustomBadge customBadgeWithString:#"$2.99"
withStringColor:[UIColor whiteColor]
withInsetColor:[UIColor redColor]
withBadgeFrame:YES
withBadgeFrameColor:[UIColor whiteColor]
withScale:1.0
withShining:NO];
// copy the graphics of the badge into a UIImage
UIGraphicsBeginImageContext(customBadge.bounds.size);
[customBadge.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// position the UIImageView at the top right hand side of the button
UIImageView* badgeHolder = [[UIImageView alloc] initWithFrame:CGRectMake(self.btnUpgrade.frame.size.width - customBadge.frame.size.width + 15, -15, customBadge.frame.size.width, customBadge.frame.size.height)];
// put the badge's image in a UIImageView
[badgeHolder setImage:viewImage];
[self.btnUpgrade addSubview:badgeHolder];

How to change the font size of the text on a UISegmentedControl?

Following is the code for initializing my UISegmentedControl.
- (void)initializeToolButtons
{
NSArray *buttonTitles = [NSArray arrayWithObjects:#"ANNEXET", #"HOVET", #"GLOBEN", "ALL", nil];
toolbuttons = [[UISegmentedControl alloc] initWithItems:buttonTitles];
toolbuttons.segmentedControlStyle = UISegmentedControlStyleBar;
toolbuttons.tintColor = [UIColor darkGrayColor];
toolbuttons.backgroundColor = [UIColor blackColor];
toolbuttons.frame = CGRectMake(0, 0, 320, 30);
[toolbuttons addTarget:self action:#selector(toolButtonsAction) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:toolbuttons];
}
How can I reduce the font size for each item on the UISegmentedControl?
Note: toolButtons has already been declared globally.
Very simple:
UIFont *Boldfont = [UIFont boldSystemFontOfSize:16.0f];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:Boldfont forKey:UITextAttributeFont];
[segment setTitleTextAttributes:attributes forState:UIControlStateNormal];
Consider re-designing your interface or use the "tab" style which has a smaller font. Messing with unexposed properties might get your app rejected or break your app if they change something under the hood.
For example the code sample given doesn't work. When you tap on a segment the font for that segment gets reset to its normal size. Anything unpredictable can happen or change in your app if you do things that deviate from the normal useage of these things. So if you want an app that will continue working in following OS updates stick with the standard stuff, or make your own controls with UIButtons and rectangular background images. A hack might work now, but its not to say it will in the future.

Resources