I've subclassed an UIAlertView as follow:
#interface NarrationAlertView : UIAlertView {
UIImage * backgroundImage; //The image I want as custom background
UILabel * textualNarrationView; //The test I wanna be displayed on the view
}
And implemented it this way :
- (id)initNarrationViewWithImage:(UIImage *)image{
if (self = [super init]){
UILabel * alertTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
self.textualNarrationView = alertTextLabel;
[alertTextLabel release];
[self addSubview:alertTextLabel];
}
return self;
}
- (void)drawRect:(CGRect)rect {
/* Here I draw the image as background */
CGSize imageSize = self.backgroundImage.size;
[self.backgroundImage drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
}
- (void)layoutSubviews {
/* To fit the text */
[textualNarrationView sizeToFit];
CGRect textRect = textualNarrationView.frame;
textRect.origin.x = (CGRectGetWidth(self.bounds) - CGRectGetWidth(textRect)) / 2;
textRect.origin.y = (CGRectGetHeight(self.bounds) - CGRectGetHeight(textRect)) / 2;
textRect.origin.y -= 70;
textualNarrationView.frame = textRect;
}
- (void)show{
/* Showing the view */
[super show];
CGSize imageSize = self.backgroundImage.size;
self.bounds = CGRectMake(0, 0, imageSize.width, imageSize.height);
}
On the previous versions of iOS (I'm always testing on the simulator) the subclass run fine and when shown it displayed the custom background image drawn correctly and just text upon it, whereas in the 4.2 version it draws the UIAlertView classic background (the blue rounded corners rectangle) on top of my image.
What am I doing wrong? Any suggestion about UIAlertView programming and UIView too will be appreciated.
UPDATE Has anyone got some UIAlertView replacement class to share?
We had a similar problem with UIAlertView in iOS 4.2; we were customizing the layout, added text boxes and rearranging the buttons.
This won't be a popular answer, but due to the changes to UIAlertView, we had to abandon using it entirely for this purpose. We always knew it was a fragile implementation since customizing/subclassing UIAlertView isn't officially supported and makes assumptions about the internal structure of the view hierarchy, but the release of 4.2 really kicked us into gear.
In the end, we implemented our own UI element to replace the customized UIAlertView.
Prior to iOS 4.2 UIAlertView's standard dark blue rounded rectangle was drawn in drawRect. the rounded rectangle could be removed by subclassing UIAlertView and implementing drawRect without calling super. however in 4.2 the rounded rectangle is a UIImageView subview.
the quick, easy (not best) solution: If you are not adding any UIImageView instances to your UIAlertView subclass you can simply remove the default UIImageView that is loaded by observing subview additions:
- (void)didAddSubview:(UIView *)subview {
if ([subview isMemberOfClass:[UIImageView class]]) {
[subview removeFromSuperview];
}
}
I got burned by this too. I ended up writing a replacement class, which I'm sharing on github:
https://github.com/TomSwift/TSAlertView
Related
I want to improve a super cool text view with placeholder and add to it super cool frame like textField has. To do it you simply need to add this code to your awakeFromNib method:
- (void)awakeFromNib
{
[super awakeFromNib];
if (self.editable) {
CALayer *selfLayer = self.layer;
UIImage *stretchableImage = [UIImage imageNamed:#"TextView"];
selfLayer.contents = (id)stretchableImage.CGImage;
selfLayer.contentsScale = [UIScreen mainScreen].scale; // Needed for the retina display, otherwise our image will not be scaled properly.
selfLayer.contentsCenter = CGRectMake(0.5, 0.5, 1.0/stretchableImage.size.width,1.0/stretchableImage.size.height);
self.backgroundColor = [UIColor clearColor];
}
}
The problem is if you add this if() to the above mentioned placeholderTextView's awakeFromNib the drawRect method of the placeholderTextView does not getting called! WHY ? Is it because of accessing layer property of this view? Please guide me through this graphics stuff..!
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
I see that few apps are extending keyboard but I would like to know how they do it.
Here are 2 examples.
Textastic &
Prompt
Now I know that I can add inputAccessoryView to UITextView but it still has small thin line that separates keyboard from UIToolbar like on image bellow.
How they do it? Extending UIWindow that holds keyboard or in some other way?
Update 1 with answer:
So I have used solution that Tyraz wrote.
Subclass UIToolbar
Instead of image I have used UIView with background color same as the finishing color of the keyboard gradient and with UIViewAutoResizingMaskFlexibleWidth so that it covers keyboard when rotated, with height of 3 pixels
Here is the code for the subclassed UIToolbar
- (void)didMoveToSuperview {
[self.separatorHideView removeFromSuperview];
CGRect seperatorRect = CGRectMake(self.frame.origin.x,
self.frame.size.height,
self.frame.size.width,
3.0);
self.separatorHideView = [[UIView alloc]];
self.separatorHideView.backgroundColor = [UIColor colorWithRed:0.569 green:0.600 blue:0.643 alpha:1.000];
self.separatorHideView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self addSubview:self.separatorHideView];
}
Update 2: Here is code how I'm adding it to UITextView and what color I'm using for tint.
I'm adding it to the UITextView in viewDidLoad with following code
CustomToolbar *accessoryToolbar = [[CustomToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 38)];
accessoryToolbar.tintColor = [UIColor colorWithRed:0.569 green:0.600 blue:0.643 alpha:1.000];
editor.inputAccessoryView = accessoryToolbar;
And this is how it looks like with solution applied to it
On iOS 7 you can create an inputAccessoryView to match keyboard style easily:
[[UIInputView alloc] initWithFrame:<#frame#>
inputViewStyle:UIInputViewStyleKeyboard];
I would try to use a inputAccessoryView plus a second view that sits on top of the separator line and "fills the gap".
Once the inputAccessoryView is added to the keyboard (overwrite the didMoveToSuperview method in your accessory UIView subclass to get notified when this happens), add it to the inputAccessoryView's superview.
Should be something like that in your accessory UIView subclass:
- (void)didMoveToSuperview {
[self.separatorHideView removeFromSuperview];
CGRect seperatorRect = CGRectMake(self.frame.origin.x,
self.frame.origin.y + self.frame.size.height,
self.frame.size.width,
2.0);
UIImage *gapGradient = [UIImage imageNamed:#"GapGradient"];
self.separatorHideView = [[UIImageView alloc]initWithImage:gapGradient];
self.separatorHideView.frame = seperatorRect;
[self.superview addSubview:self.separatorHideView];
}
I would also overwrite setFrame in your accessory UIView subclass to update the frame of the gapView in case the frame of the keyboard is changed.
I'm trying to make a subclassed UITableViewCell where I draw an image in the upper right corner. I have it working perfectly - except when I set self.backgroundView, my background image covers up the image drawn in drawRect.
There must be a way to be able to set a background image (and the selectedBackgroundView) without covering up what's being done in drawRect.
Am I going about this the wrong way?
EDIT: I've posted an example project with the problem.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
// TODO: figure out why this covers up self.starImage that's drawn in drawRect
self.backgroundView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cellBackground.png"]] autorelease];
}
return self;
}
- (void)drawRect:(CGRect)rect {
[self.starImage drawAtPoint:CGPointMake(self.bounds.size.width - self.starImage.size.width, 0.0)];
}
EDIT 2: at AWrightIV's request, here's how I got it working... which didn't require subclassing UITableViewCell at all. I'm just adding a subview to cell.backgroundView:
// create a UIImageView that contains the background image for the cell
UIImageView *bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cellBackground.png"]];
// create another UIImageView that contains the corner image
UIImage *starRedImage = [UIImage imageNamed:#"starcorner_red.png"];
UIImageView *starImageView = [[UIImageView alloc] initWithFrame:CGRectMake(297,
0,
starRedImage.size.width,
starRedImage.size.height)];
starImageView.image = starRedImage;
// add the corner UIImageView as a subview to the background UIImageView
[bgImageView addSubview:starImageView];
// set cell.background to use the background UIImageView
cell.backgroundView = bgImageView;
You are not really supposed to mix the drawing with your cell like that, you are operating at a lower-level than the UITableViewCell machinery is operating, and this is why you get this problem.
This is just one of the various problems you will end up running into. You will run into other problems as you go down that path, including problems with how the selection works.
The proper approach is to create a custom UIView that contains the code to draw, and then you can addSubView that into your cell's root view. That will take care of the rendering in the proper order, and wont interfere with the selection system, and will work correctly in this case.
You shouldn't override the -drawRect: of a tablecell. Instead, create a new custom view and add it to the cell's contentView, and draw in there.
Have you tried adding a [super drawRect:rect]; there?
Here's a solution that's a bit of a kludge, but it fits my requirements exactly... with one fatal flaw: when cells get reused, the star corner shows up when I don't want it to.
http://dl.dropbox.com/u/2349787/UIImage_Position_subclassed_cell2.zip
I'm still using drawRect here, but only because self.starImage is null if you access it within the initWithStyle method. Also, instead of adding the subview to self.contentView, I'm adding it to self.backgroundView to prevent the cell's delete button from interfering with it. The star corner is positioned correctly in both portrait and landscape mode, and works fine within edit mode as well.
With the cell reuse issue though, It's still a no go... so, maybe I'm back to trying to do it without subclassing UITableViewCell.
I'm open to any further suggestions. Thank you!
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
// Initialization code
self.backgroundView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cellBackground.png"]] autorelease];
}
return self;
}
- (void) drawRect:(CGRect)rect {
UIImageView *imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(self.bounds.size.width - self.starImage.size.width, 0, self.starImage.size.width, self.starImage.size.height)] autorelease];
imageView.image = self.starImage;
imageView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[self.backgroundView addSubview:imageView];
}
The UISwitch on my device: Switch Image with the bottom pixels cut off http://gorgando.com/uiswitch.jpg
The UISwitch on the simulator: Good UISwitch http://gorgando.com/uiswitch-good.png
As you can see, the bottom pixels are cut off on the device, but not on the simulator. I have tried just about everything I can think of, but nothing has fixed the problem.
Some of the things I've tried:
Changing the UISwitch's frame's height
Changing the UICell's height
Changing the UICell's contentView's height
Adding the UISwitch to the UICell rather than the UICell's contentView
Here is the relevant code:
This is in the viewDidLoad of the uiTableViewController:
UISwitch *sw = [[UISwitch alloc] init];
self.contactedSwitch = sw;
[sw release];
self.contactedSwitch = [UISwitch switchWithLeftText:#"YES" andRight:#"NO"];
self.contactedSwitch.center = CGPointMake(230, 22);
self.contactedSwitch.on = [self.contact.contacted boolValue];
This is where the switchWithLeftText:andRight method comes from:
#import "UISwitch-Extended.h"
#define TAG_OFFSET 900
#implementation UISwitch (tagged)
- (void) spelunkAndTag: (UIView *) aView withCount:(int *) count
{
for (UIView *subview in [aView subviews])
{
if ([subview isKindOfClass:[UILabel class]])
{
*count += 1;
[subview setTag:(TAG_OFFSET + *count)];
}
else
[self spelunkAndTag:subview withCount:count];
}
}
- (UILabel *) label1
{
return (UILabel *) [self viewWithTag:TAG_OFFSET + 1];
}
- (UILabel *) label2
{
return (UILabel *) [self viewWithTag:TAG_OFFSET + 2];
}
+ (UISwitch *) switchWithLeftText: (NSString *) tag1 andRight: (NSString *) tag2
{
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 94, 27)];
int labelCount = 0;
[switchView spelunkAndTag:switchView withCount:&labelCount];
if (labelCount == 2)
{
[switchView.label1 setText:tag1];
[switchView.label2 setText:tag2];
}
return [switchView autorelease];
}
#end
This is where I add the UISwitch to my tableviewcell:
[[contactedCell contentView] addSubview:self.contactedSwitch];
Thanks so much!
[Update] I thought the tableviewcell's might be the problem, so I added these UISwitches to a regular UIView to see how they looked. I have the exact same problem where they look alright in the simulator and the bottom is chopped in the device. So bizarre!
I had the same problem when programatically creating a UISwitch and changing its frame's origin- it turned out to be a half-pixel issue.
A key to noticing half-pixel bugs is: do the unwanted artifacts appear differently on the simulator vs device?
Your solution of placing the UISwitch with Interface Builder fixes this- you can also make sure to floor() your new coordinates if you are setting the UISwitch's frame's origin x/y.
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame(CGRectZero)];
CGRect switchFrame = mySwitch.frame;
// move frame up without pixel fractions
switchFrame.origin.y = floor((cell.contentView.frame.size.height - switchFrame.size.height) / 2);
mySwitch.frame = switchFrame;
[cell.contentView addSubview:mySwitch];
In the original poster's case, the height of a uiswitch is an odd number (27 pixels), so setting the center to 22 splits the height into 13.5. The UISwitch's origin's y coordinate becomes 22-13.5 = 8.5 pixels. Either don't move a UISwitch by setting its center, or floor the coordinate, or use a fraction in the call to CGPointMake(230,22.5).
Another way to track this type of bug is to grep through Interface Builder looking for ".5" coordinates. I have found that sometimes over-tweaking the placement of UI elements in Interface Builder introduces this bug.
This is caused of the UISwich's top.
You can use UISwich.origin.y = ceil((height - UISwich.size.height)/2)
to fix it.
Never figured out exactly what was wrong, but I ended up creating the UISwitches in IB and got it to work beautifully that way. Very weird that it works in IB and not programmatically when I am basically doing the exact same thing.