Adding a sub-view appears to do nothing - objective-c

In my application, when the user clicks an infoButton, it should add another view to the screen at a specific location. I'm trying to achieve this behavior with the following method:
- (IBAction)showInfo1:(id)sender
{
UIView *myView1 = [[UIView alloc] initWithFrame:CGRectMake(25,25,50,20)];
[self.view addSubview:myView1];
}
(I declared everything in the header file of my class.)
When I run the code and press the button, nothing appears to happen (I don't see the new view).
I also noticed that XCode is displaying the following warning:
Local declaration of 'myView1' hides instance variable.
Does anyone have any ideas?

How do you know nothing changes?
It looks like myView1 doesn't actually contain anything. Try setting the background color of myView1
- (IBAction) showInfo1: (id) sender
{
UIView *myView1 = [[UIView alloc] initWithFrame:CGRectMake(25,25,50,20)];
myView1.backgroundColor = [UIColor redColor];
[self.view addSubview: myView1];
}
To open it at a specific point you need to change the parameters in CGRectMake() for example
to open it at the very top left with a width of 50 and height of 20 you would do:
CGRectMake(0, 0, 50, 20)

"Local declaration of 'myView1' hides instance variable." message appears because you have declared in your class some property with the same name (even if the type is different).
If you put UIView *myView1 in your class definition, your method would look like
- (IBAction)showInfo1:(id)sender{
myView1 = [[UIView alloc] initWithFrame:CGRectMake(25,25,50,20)];
[self.view addSubview:myView1];
}
Here comes more considerations: you must to release myView1 when you stop using it, avoid to be placed more than once, etc. but here we have the basic idea.
Finally, maybe your view is already added, but 'cause it doesn't contains anything yet, you don't notice it. Also you would like to check UIViewController to see if works better for you.

Related

UIButton setting frame not working?

I have written the following code for my app:
self.PlayButton = [[UIButton alloc] init];
//Setup Play Button
[self.PlayButton setTranslatesAutoresizingMaskIntoConstraints:NO];
self.PlayButton.frame = CGRectMake(self.view.frame.size.width * 0.38, self.view.frame.size.height * 0.666, self.view.frame.size.width * 0.48, self.view.frame.size.height * 0.29);
[self.PlayButton setBackgroundImage:[UIImage imageNamed:#"PlayButton.png"] forState:UIControlStateNormal];
[self.PlayButton.layer setMagnificationFilter:kCAFilterNearest];
[self.PlayButton addTarget:self action:#selector(PlayButtonMethod) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside]
[self.view addSubview:self.PlayButton];
But when this code it run rather than the image appearing in a rather specific location it simply appears in the top left hand corner of the view. Almost like it had been set
self.PlayButton.frame = CGRectMake(0, 0, self.view.frame.size.width * 0.48, self.view.frame.size.height * 0.29);
It's odd because the width and height is put in correctly but for whatever reason the position of the button set by the CGRectMake is not taken into account. Ive done a bit of research into creating UIButtons in code and fro what I've seen not only has this happened to no-one else the code have written is perfectly liable.
Any help would be appreciated.
Thanks
Looks like ive found the fix:
Removing this line of code fixed the issue for me.
[self.PlayButton setTranslatesAutoresizingMaskIntoConstraints:NO];
not 100% sure why this was causing the problem but it fixed it.
When creating UIButtons using the standard alloc init method doesn't actually create a button. The method for creating and initializing a UIButton is called buttonWithType:. This creates a UIButton of the specified type if you use alloc init it will not work correctly, see the Apple Documentation for UIButton.
So you need to change line
self.PlayButton = [[UIButton alloc] init];
to
self.PlayButton = [UIButton buttonWithType:UIButtonTypeCustom];
buttonWithType: allows you to pass in an enum of UIButtonType so it will accept any of the following values :
UIButtonTypeCustom
UIButtonTypeSystem
UIButtonTypeDetailDisclosure
UIButtonTypeInfoLight
UIButtonTypeInfoDark
UIButtonTypeContactAdd
UIButtonTypeRoundedRect
If you don't pass it a UIButtonType the button will not be initialized as it will not know what type of button you want and it will not assume. Also check out the Apple Documentation for UIButtonType
Side Note
I'm just going to include this as a side note. Also have a read of the Apple Coding Conventions Documentation as I have noticed that you are using uppercase to start your variable names (i.e. PlayButton). Variable names should start with lowercase (i.e. playButton) and Class and Enum names should start with uppercase (i.e. UIViewController). It's always good to stick to conventions as it makes you code more readable and maintainable so if another developer comes to modify your code it is easy for them or even yourself to read.

UIView creation and positioning

I have in my controller two UIView members, progressLineView and buttonsView. At some point I call this method:
- (void) drawPlayProgressLine{
progressLineView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 1, buttonsView.frame.size.height)];
progressLineView.backgroundColor = [UIColor whiteColor];
[buttonsView addSubview:progressLineView];
}
Everything works fine, and I also have a method that changes the position of the view:
- (void) moveProgressLine{
CGRect frame = progressLineView.frame;
frame.origin.x++;
progressLineView.frame = frame;
}
After the moveProgressLine method is called a few times and I want to call drawPlayProgressLine again, instead of completely moving the view to the starting position, it creates a new view. The more drawPlayProgressLine is called, the more views I get on my screen but I only need one.
I don't understand how this can happen when I'm creating only one object. How can I move the view instead of having a new one created each time? And another question: how can completely remove it (until the drawPlayProgressLine method is called to create it again)
I don't understand how this can happen when I'm creating only one object.
You create a new view every time you call your -drawPlayProgressLine method. Call it 10 times, you get 10 views.
How can I move the view instead of having a new one created each time?
Don't create the view each time through -drawPlayProgressLine. Instead, you can do either of:
Create progressLineView once, when the view controller's view hierarchy is created. -viewDidLoad is a perfect place for that sort of thing.
Check the value of progressLineView and create it only if it is currently nil.
Whichever you choose, assuming progressLineView is an instance variable, you can do exactly what you're doing in your -moveProgressLine method. That is, just use progressLineView as though it already exists, because it does. BTW, an easy way to move a view is to modify it's center property:
CGPoint *c = progressLineView.center;
c.x += 25.0;
progressLineView.center = c;
And another question: how can completely remove it (until the
drawPlayProgressLine method is called to create it again)
One approach is to simply hide the view when you're not using it. Another is to remove it from its super view (and release it if you've retained it), and then set your progressLineView to nil. So, if progressLineView is an ivar, do this:
[progressLineView removeFromSuperview];
[progressLineView release]; // if you're not using ARC and have retained it
progressLineView = nil;
you should just check if its created yet before creating it and move it if necessary:
- (void) drawPlayProgressLine{
if(progressLineView == nil)
{
progressLineView = [[UIView alloc] init];
progressLineView.backgroundColor = [UIColor whiteColor];
[buttonsView addSubview:progressLineView];
}
progressLineView.frame = CGRectMake(0.0, 0.0, 1, buttonsView.frame.size.height);
}
You are probably not invalidating the parent view. New objects are not created, but rather their presentation is left on the screen after you move them.
As for the second question:
[progressLineView removeFromSuperview];
[progressLineView release];
progressLineView = nil;

Code copied from one file to another will not build

I have some code that sets a border around a UITextView. It builds correctly in one class; when I take that code and copy it to another class (changing the object name), it no longer builds, saying "Property 'borderWidth' cannot be found in forward class object 'CALayer *'" (the same message for the other two lines of code). I have done a clean, re-build and nothing helps. Why is this happening? and how do I fix it?
- (void)viewDidLoad {
[super viewDidLoad];
//-- draw box around notes field
orderNotes.layer.borderWidth = 1.0f;
orderNotes.layer.borderColor = [[UIColor blackColor] CGColor];
orderNotes.layer.cornerRadius = 4;
}
Object "orderNotes" is defined as UITextView. There are no other errors.
You need to:
#import <QuartzCore/QuartzCore.h>
Otherwise, the layer property is not visible to you.

setting an accessibilityLabel on a UIImageView contained in UITableView header

I have a UITableView that I build in loadView. One of the things I do in loadView is create a UIView to act as the table header and stuff a UIImageView into it. The image view contains an image that is a stylized title, so I want to add an accessibility label for VoiceOver users. However, I can't get VoiceOver to "focus" on the image in order to read the label, and the Accessibility Inspector doesn't respond to clicking on the image in the simulator. My (abbreviated) code follows:
... in -loadView ...
// Make header view
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(...)];
UIImageView *titleImageView = [[UIImageView alloc] initWithImage:[self titleImage]];
titleImageView.accessibilityLabel = [self accessibilityLabelForTitleImage];
[headerView addSubview:titleImageView];
// Make table view
self.tableView = [[UITableView alloc] initWithFrame:CGRect(...) style:UITableViewStylePlain];
self.tableView.tableHeaderView = headerView;
... code continues ...
I've stepped through in gdb and accessibilityLabelForTitleImage returns a string. po [titleImageView accessibilityLabel] prints out the correct string, but I'm still unable to focus on the image view. Note that the views themselves appear and respond as appropriate.
Am I missing something? Is there a way to force VoiceOver to acknowledge an image view?
In Voice-Over , in order to make an element accessible :-
you have to set setIsAccessibilityElement property as true which i don't find in your code.
The other important point is that to make child elements (subviews) to be accessible , you have to seperately make them accessible while the parent should not be accessible(you have to specify this also).
Implement the UIAccessibilityContainer Protocol in your custom - cell.
It will be a big story if i go on .Please refer this Accessibility voice over by apple.
Hope this helps.
I used KIF for testing my IOS app. In my tableview, I assigned value to tableview.accesssibilityIdentifier instead of tableview.accessibilityLabel. It worked for me. Wanna give it a try?
Voice-Over sometimes can get nasty and just by setting isAccessibilityElement might not work.
In this case try setting accessibilityElements on the parent view and include the child views in the array, like this:
parentView.accessibilityElements = [childView1, childView1, childView1]
Doing it also ensures that the accessibility items are being read in the order you want.

Setting background color of UIView subclass doesn't work

I'm trying to change background color of one of my UIView subclasses. For some reason self.backgroundColor = [UIColor whiteColor];doesn't do anything when I put it in my - (id)initWithFrame:(CGRect)framemethod inside the view. The view is always black. I have also tried self.myView.backgroundColor ... from my view's controller, but that didn't work either. Any ideas on what I'm doing wrong?
The relevant code looks like this:
[...]
#interface PaperView : UIView
[....]
[...]
#implementation PaperView
[...]
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[...]
// Initialization code
self.backgroundColor = [UIColor whiteColor]; // This doesn't do anything, the view is always black.
}
return self;
}
If this view is being unarchived from a xib, you need to override -initWithCoder:. -initWithFrame: is only invoked if you are creating your view programmatically.
I had this same problem. I hooked into layoutSubviews() and it worked ok:
override func layoutSubviews() {
super.layoutSubviews()
self.backgroundColor = UIColor.clearColor()
}
This is indicative of the view not having a frame set to it. I recommend setting a breakpoint in your initWithFrame: to verify that its being called. If you were to call, say, ... = [UIView alloc] init], then that could be the source of your problem.
EDIT
If initWithFrame: is in fact being called, it's possible that the view is being covered by another view giving the appearance that it's not working (since you don't see it) or that the view itself is hidden.
Another way to troubleshoot is to override the backgroundColor property and set a breakpoint. Find out what else, in the callstack, is changing the color.
You may use self.layer.backgroundColor instead:
mySubclassedView.layer.backgroundColor = UIColor.green.cgColor
In what method do you call self.myView.backgroundColor?
Are you sure, that it's after viewDidLoad: ?
But, have no idea what is wrong with your first method.
Could you show more code?
I just had this exact same problem. The background color did not show even though I set the correct frame and set the background color to white in my custom init method, as well as in my viewWillAppear method. I also verified that nothing was covering it.
Then I found the solution: I set the background color in viewDidAppear instead, and all was fine:
- (void)viewDidAppear:(BOOL)animated
{
[self.view setBackgroundColor:[UIColor whiteColor]];
self.view.frame = _viewFrame;
}
(The _viewFrame CGRect was passed in to my init method.)
Another option is to set it in - (void)viewDidLayoutSubviews, depending on when and how exactly you want to set your background color.
To be entirely honest, I don't understand (yet) why setting the background color in viewDidAppear worked while it didn't work in the init method, and the code for setting it was identical in both places.
Hope this helps,
Erik
UPDATE:
It does have something to do with view's frame. When I set my view's frame in my init method, then setting the background color in the viewDidAppear no longer has the desired effect. This is even the case if I set my view's frame after my view build method that creates the sub views. So the real mystery is: between the point where I am done creating my view and the point where it is displayed, what in the view's life cycle is causing the view's frame to be reset to something that is incorrect?
So, the answer really is: it will work as long as your frame is set correctly and your view is visible. Just check your view's frame throughout the view's lifecycle to make sure it's correct.
Tricky...
Why can't you implement self.backgroundColor = [UIColor whiteColor] in -viewDidLoad method instead of -initWithFrame? Then try self.backgroundColor = [UIColor whiteColor]; as well as self.myView.backgroundColor to see which works.