Can't change the frames of .xib UI objects in code - objective-c

I am trying to re-write my code to allow me to use xibs to design custom UIViews for re-use throughout my projects. I have created a class called SlidesView which has a .xib of the same name. I have set it up using the following IBOutlets:
#property (nonatomic, retain) IBOutlet UIImageView *ivMain;
#property (nonatomic, retain) IBOutlet UILabel *lHeader;
#property (nonatomic, retain) IBOutlet UITextView *tvMain;
#property (nonatomic, retain) IBOutlet UIImageView *ivIcon;
I have made sure these are all properly connected within the .xib file. I also have a function which I want to use to setup all the initial data for the view:
- (void)setupUsingCenter:(CGPoint)center mainImage:(UIImage *)mainImage mainText:(NSString *)mainText header:(NSString *)header andIconImage:(UIImage *)iconImage
The 'setupUsingCenter:self ...' body looks as follows:
// First check for a main image and image icon
if (mainImage != nil)
{
// Set the image
[self.ivMain setImage:mainImage];
[self.ivMain setFrame:CGRectMake(10, 10, 10, 10)];
// If image icon set that too
if (iconImage != nil)
{
[self.ivIcon setImage:iconImage];
}
}
And finally I load this .xib using the following code:
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"SlidesView" owner:nil options:nil];
for (UIView *view in views) {
if([view isKindOfClass:[SlidesView class]])
{
SlidesView *slidesView = (SlidesView *)view;
[slidesView setupUsingCenter:self.vPlaceholder.center mainImage:slideImage mainText:slideText header:slideTitle andIconImage:slideIcon];
[slidesView setTextColours:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f]];
[self.view addSubview:slidesView];
self.viewPopup = slidesView;
}
}
I have put in the random setFrame parameters for testing purposes but for some reason the frame doesn't change. However, the image on the ivMain does change. Can anyone explain how I can change the frame for my UI objects? Also, why does it allow me to change the image but the frame seems un-editable, doesn't this mean it must be initialised?
Any help is much appreciated,
Thanks.

Are you sure autolayout is disabled on the .xib ? It is my understanding that you cannot edit frames when autolayout is on.
If that's the case, you can either disable autolayout for that particular .xib, or you can work on constraints instead of the frame property

The use of autosizing may cause some unexpected behaviors also the autoresize subviews.
You can try something like this:
[View setAutoresizingMask:UIViewAutoresizingNone];
And:
[View setAutoresizesSubviews:NO];
Where View is the UIView that you want to apply that behavior.

Related

UIImageView not showing up

I have a UIImageView with property, it's connected in the storyboard and in viewDidLoad I have set it's image. I first create an image then assign it to the image of the UIImageView.
-(void)viewDidLoad {
[super viewDidLoad];
UIImage *image = [[UIImage imageNamed:#"image"]resizeableImageWithCapInsets:UIEdgeInsetsMake(28.5, 5, 6.5, 5)];
[self.imageView setImage:image];
}
I've made sure numerous times that the UIImageView is connected in the IB and it's showing up as connected. I have a UICollectionView over it, but it doesn't extend high enough to cover it all and the UICollectionView background color is set to clear. Thanks in advance for the help.
I suppose you added the IBOutlet UIImageView * imageView in your .h and then linked it in the Interface Builder, BUT did you add the property of the imageView? Like this:
#property (nonatomic, retain) IBOutlet UIImageView * imageView;
And then in your .m file, under the #implementation you need to add #synthesize imageView;
and set the image to your imageView using only: [imageView setImage:image]; (without the self.).
(You can also skip the #synthesize and just use [_imageView setImage:image];)
The #property allows you to edit the properties of the object, like backgroundColor, alpha, image, etc.

Why isn't initWithCoder initializing items correctly?

I've got a subclass of UITableViewCell. My subclass contains several UILabels. I want my subclass to initialize these labels to some default settings that applies to every table view cell of mine.
I read that I should be using initWithCoder for this. My initWithCoder function is being called, and I can step through each line in my function and it appears to go through the motions. When I run my application I do not see any of the properties being applied, though. Most noticeably, the font is not being changed. I just don't think any of the properties that I'm modifying on my UILabels are actually being saved, or displayed.
I'm using this subclass in conjunction with a Storyboard. I know my changes will not be reflected on the Storyboard, but they're also not being reflected when the application runs - despite my code being executed.
Edit: I wanted to mention that prior to trying to override initWithCoder, I had an instance method in these subclasses that I'd run this logic in. I would just call that instance method inside of cellForRowAtIndexPath. This method was working, but I thought it'd be handy to have this logic in this subclass occur automatically.
Any ideas? My code is below:
#import "ThreadListCell.h"
#implementation ThreadListCell
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
// adjust the font settings of the title
self.title.font = [UIFont fontWithName:#"SourceSansPro-Black" size:16];
self.title.textColor = [UIColor colorWithWhite:0.267f alpha:1.0f];
// adjust the font settings of the subtitle
self.text.font = [UIFont fontWithName:#"SourceSansPro-Light" size:14];
self.text.textColor = [UIColor colorWithWhite:0.267f alpha:0.9f];
self.text.textColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
// adjust the font settings of the location
self.location.font = [UIFont fontWithName:#"SourceSansPro-Light" size:8];
self.location.textColor = [UIColor colorWithWhite:0.267f alpha:0.9f];
// adjust the UILabel settings of the title
self.title.numberOfLines = 0;
self.title.lineBreakMode = UILineBreakModeTailTruncation;
// adjust the UILabel settings of the subtitle
self.text.numberOfLines = 0;
self.text.lineBreakMode = UILineBreakModeTailTruncation;
// adjust the UILabel settings of the location
self.location.numberOfLines = 0;
self.location.lineBreakMode = UILineBreakModeTailTruncation;
self.location.textAlignment = UITextAlignmentRight;
}
return self;
}
#end
And the header:
#import <UIKit/UIKit.h>
#interface ThreadListCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *text;
#property (nonatomic, weak) IBOutlet UILabel *title;
#property (nonatomic, weak) IBOutlet UILabel *location;
#end
None of your IBOutlets is set when you get the message - you need to use "awakeFromNib" or "viewDidLoad" - something like that - to access your outlets. That said, you can set other non-outlet stuff in the initWithCoder.

Re-using IBOutlet programmatically

I have an UIView created in IB with some labels and custom colours and linked that as an IBOutlet so I could have access to it in my viewController.
#property (strong, nonatomic) IBOutlet UIView *tile;
although I would like to create more of this outlet within a loop:
- (void)viewDidLoad {
[super viewDidLoad];
int i = 0;
while (i <= 9) {
UIView *cTile = [self.tile copy];
[self.view addSubview:cTile];
i += 1;
}
}
So I'm trying to copy this tile outlet and then add the copied view to the main view.
Apparently this can't be done and returns an error.
Is it possible to achieve such behaviour and re-use/duplicate an IBOutlet?
I dont think what you want to do is possible as UIView doesn't conform to the NSCopying protocol.
Best bet would be to create your "tile" as a UIView subclass or crate a nib for it and then you can reload it as many times as you want.

How do I access or manipulate variables of one class from another in Xcode

I am a novice to IOS programming hence struggling a bit with the below problem. I will do my best to describe the problem and any help is greatly appreciated.
I have the following created:
AboutViewController (.h, .m and .xib ) which has two subviews called - mainView, infoView. mainView and infoView interfaces are created in the XIB file.
TestView ( View to deal with initiating, toggling between mainView and infoView )
TestView.h is as follows:
#interface TestView : UIView {
IBOutlet UIView *mainView;
IBOutlet UIView *infoView;
UILabel *lbltitle;
UIImageView *imgIcon;
IBOutlet UITextView *txtInfo1;
IBOutlet UITextView *txtInfo2;
IBOutlet UITextView *txtInfo3;
}
#property (nonatomic, retain) IBOutlet UILabel *lbltitle;
#property (nonatomic, retain) IBOutlet UIImageView *imgIcon;
TestView.m is as follows:
#import "TestView.h"
#import <QuartzCore/QuartzCore.h>
#implementation TestView
#synthesize lbltitle, imgIcon;
-(void)awakeFromNib
{
[self addSubview:mainView];
}
In portrait mode the views are working great but when it comes to landscape mode, the views are all kinda screwed up. I tried to use the XIB but I guess you can only do so much so I decided to do this programmatically.
In the AboutViewController.m, I am trying to override willAnimateRotationToInterfaceOrientation method and place the objects based on the orientation. When I put breakpoints, I can see that code is being called except it is not translating into the UI i.e., no change in the UI. What am I doing wrong ? Should I be approaching this in a different way. Any suggestions or guidance is greatly appreciated.
- (void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
TestView *t = [[TestView alloc]init];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
[t.imgIcon setFrame:CGRectMake(10,74,165,190)];
[t.lbltitle setFrame:CGRectMake(20, 10, 387, 21)];
}
else
{
[t.imgIcon setFrame:CGRectMake(10,74,165,190)];
[t.lbltitle setFrame:CGRectMake(189, 10, 387, 21)];
}
}
Well the particular problem is you manipulate a view that you just created using
TestView *t = [[TestView alloc]init];
You don't display the view anywhere, so it sits in memory. You can apply all changes you want, but to be able to see them, you must first display the view:
Find the appropriate parent and do:
[parentview addSubview:t];
In more general terms you shouldn't be creating new views in the rotation handling code.

Setting the initial value of a UILABEL

I'm trying to create a simple Quiz app (I'm a beginner), when I launch the app I want a UILabel to show the first question (of an array of questions). I'm having some trouble with setting the initial value.
I've done a couple of attempts, whiteout success. I my QuizAppDelegate.h file I declare my UILabel like this:
IBOutlet UILabel * questionField;
In my main .m file I have tried the following:
- (id)init {
[super init];
questions = [[NSMutableArray alloc] init];
// Not working
questionField = [[UILabel alloc] init];
[questionField setText:#"Hello"];
// Working
NSLog(#"Hello");
[self defaultQuestions];
// [self showQuestion];
return self;
}
Another thing I have tried is the following in QuizAppDelegate:
#property (nonatomic, retain) IBOutlet UILabel *questionField;
- (void)changeTitle:(NSString *)toName;
And in the .m file:
#synthesize questionField;
- (id)init {
[super init];
questions = [[NSMutableArray alloc] init];
// Not working
[self changeTitle:#"Hello"];
// Working
NSLog(#"Hello");
[self defaultQuestions];
// [self showQuestion];
return self;
}
-(void)changeTitle:(NSString *)toName {
[questionField setText:toName];
}
Any tips on how to solve this would be great!
// Anders
Hopefully you're not actually putting code into main.m. On iOS, you rarely modify that file.
Since you're doing everything in the AppDelegate, let's keep it there (as opposed to creating a new UIViewController). Let's start with the basics.
Adding the Label as an instance variable
You're doing this correctly—inside the curly braces of the .h file, put the line
IBOutlet UILabel * questionField;
Then, declare the corresponding property, and make sure to synthesize it in the .m file.
#property (nonatomic, retain) IBOutlet UILabel *questionField;
#synthesize questionField // in the .m file
Adding the UILabel in Interface Builder
Open up MainWindow.xib. Drag a UILabel from the Library to the Window that represents your app's window. Then Control-Drag from the AppDelegate object (the third icon on the left in Xcode 4; it'll be labelled in the Document window in IB 3). You'll see a little black window come up—select the option called questionField to make the connection.
See this link for screenshots and how to make connections in IB. The same applies in Xcode 4.
Changing the text
You don't need a separate method to change the text—just modify the label's text property.
Pick a method that'll be called when the app launches (applicationDidFinishLaunching:WithOptions: is a good place to do it in), and put the following code:
questionField.text = #"Hello";
And that's it!
Code
QuizAppDelegate.h
#import <UIKit/UIKit.h>
#interface QuizAppDelegate : NSObject <UIApplicationDelegate> {
IBOutlet UILabel *questionField;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UILabel *questionField;
#end
QuizAppDelegate.m
#import "QuizAppDelegate.h"
#implementation QuizAppDelegate
#synthesize window=_window;
#synthesize questionField;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Add the tab bar controller's current view as a subview of the window
[self.window addSubview:self.questionField];
[self.window makeKeyAndVisible];
self.questionField.text = #"Hello";
return YES;
}
- (void)dealloc
{
[_window release];
[questionField release];
[super dealloc];
}
#end
If you're creating the label programmatically, then you have to add the label to the view:
[self.view addSubview:questionField];
This assumes that you have a ViewController. If not, and you're doing this directly in the AppDelegate (a very bad idea, by the way), then do
[self.window addSubview:questionField];
If you're creating it in the IB, make sure you set up the connections.
You should not both add the UILabel in the IB and instantiate it programmatically. Only call alloc if you are creating it programmatically. Otherwise, if using the IB, skip that part. You created it already with the xib.
I suspect that you have either not created your Interface Builder layout properly - either you have missed the control out all together or more likely you have not connected that control to the questionField outlet in yout header file.
You need to drag a UILabel view into the main view and then connect it to the correct line in your header file.
You shouldn't be using your main.m like that at all. In fact, you should almost certainly never do anything with it. Try creating a UIViewController subclass and practicing your quiz with that. (Add the UILabel to the IB file and then connect the outlet.) Perhaps use the View-Based Application template while you are practicing.
This is a good answer:
"You're doing this correctly—inside the curly braces of the .h file, put the line
IBOutlet UILabel * questionField;"
I was trying to change the value of mylabel.text and the screen didn't update the label with this.value. I included the {IBOutlet UILabel * mylabel} and it works like a charm!
So this answer is valid to change the text of a label programmatically!
Thanks