I have a view and I am creating a UILabel programatically and calling it my parameter passing as I need many UILabel text with Different Position frame, so I am calling it by parameter passing.
Using the code below, when I rotate to landscape mode the portrait view Label still appears. How do I overcome this? I need to be done in the below code. I want the position of the Label frame to be changed from portrait view to landscape view.
NOTE:I need to Create many Label,s around 15 to 20, so I am using parameter passing, so that I don't need to write as many methods for creating each label.
-(UILabel*)createLabel:(CGRect)frame :(NSString*)labelTitle
{
UILabel *myLabel = [[UILabel alloc] initWithFrame:frame];
[UIFont fontWithName:#"Arial" size:13];
myLabel.text = labelTitle;
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
[self.view addSubview:[self createLabel:CGRectMake(450,140,60,20):#"Ratings:"]];
[self.view addSubview:[self createLabel:CGRectMake(450,170,60,20):#"Reviews:"]];
}
else
{
[self.view addSubview:[self createLabel:CGRectMake(650,140,60,20):#"Ratings:"]];
[self.view addSubview:[self createLabel:CGRectMake(650,170,60,20):#"Reviews:"]];
}
return YES;
}
Don't create them in shouldAutorotateToInterfaceOrientation, because it will get called everytime the orientation changes, thus creating more labels.
Instead create them once in - (void) loadView, and give them the correct autoResizingMask properties, e.g:
myLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth ;
This will cause the desired behaviour when the orientation changes: the labels will automatically resize and the whole turning animation will be smooth.
PS: Mind that the way you were creating Labels is causing a memory leak, use the release method to prevent this.
The label for portrait orientation still appears because each time the device is rotated, you are adding a new label without removing the old one.
I think it is not a good idea to create new labels while you can just change the frame of the existing ones. To do this, you should add two properties (say reviewLabel and ratingLabel) to your class and assign your labels to these when they are first created. Then on your shouldAutorotate function, you can access these labels and change their frame.
Related
I am new to iPad developer,
I made one Registration form in my application, when i see my application in Portrait mode,
i am able to see whole form with no scrolling, but when i see same form in Landscape mode, i am not able to see part which is at bottom of page, for that a scrolling should be there to see bottom part.
:
In my .h file when i replace
#interface ReminderPage : UIViewController{
...
...
}
:UIViewController with :UIScrollView
and then when i add label in my .m file like this,
UILabel *Lastpaidlbl = [[[UILabel alloc] initWithFrame:CGRectMake(70 ,400, 130, 50)]autorelease];
Lastpaidlbl.backgroundColor = [UIColor greenColor];
Lastpaidlbl.font=[UIFont systemFontOfSize:20];
Lastpaidlbl.text = #"Lastpaid on :";
[self.view addSubview:Lastpaidlbl];
I am getting error on last line Property view not found on object of type classname.
i am unable to add label in my view.
Any help will be appreciated.
The question appears to be really asking how can all the components on the screen be placed inside a UIScrollView, rather than a UIView. Using Xcode 4.6.3, I found I could achieve this by simply:
In Interface Builder, select all the sub-views inside the main UIView.
Choose Xcode menu item "Editor | Embed In | Scroll View".
The end result was a new scroll view embedded in the existing main UIView, will all the former sub-views of the UIView now as sub-views of the UIScrollView, with the same positioning.
If you want to replace your UIViewController with a UIScrollView, you will have to go a bit of refactoring to your code. The error you get is just an example of that:
the syntax:
[self.view addSubview:Lastpaidlbl];
is correct if self is a UIViewController; since you changed it to be UIScrollView, you should now do:
[self addSubview:Lastpaidlbl];
You will have quite a few changes like this one to make to your code and will face some issues.
Another approach would be this:
instantiate a UIScrollView (not derive from it);
add your UIView (such as you have defined it) to the scroll view;
define the contentSize of the scroll view so to include the whole UIView you have.
The scroll view acts as a container for your existing view (you add your controls to the scroll view, then add the scroll view to self.view); this way, you could integrate it within your existing controller:
1. UIScrollView* scrollView = <alloc/init>
2. [self.view addSubview:scrollView]; (in your controller)
3. [scrollView addSubview:<label>]; (for all of your labels and fields).
4. scrollView.contentSize = xxx;
I think the latter approach will be much easier.
Please put all of your UIComponents to the UIScrollview and then it will start scrolling.
please look in to content size. please change it according to the orientation of device.
You're subclassing UIScrollView, so there is no self.view because already self is the view (of the scrollview). You dont need to subclass the scrollview, you can just embed your components in a ivar scrollview and set its contentSize (in your case, you have to enable the scrolling just when the device is in landscape mode). In interface builder you can embed the selected elements in one click, Editor-> Embed in-> scrollview.
First create scrollview
UIScrollView * scr=[[UIScrollView alloc] initWithFrame:CGRectMake(10, 70, 756, 1000)];
scr.backgroundColor=[UIColor clearColor];
[ self.view addSubview:scr];
second
change [self.view addSubview:Lastpaidlbl];
to
[scr addSubview:Lastpaidlbl];
third
set height depends on content
UIView *view = nil;
NSArray *subviews = [scr subviews];
CGFloat curXLoc = 0;
for (view in subviews)
{
CGRect frame = view.frame;
curXLoc += (frame.size.height);
}
// set the content size so it can be scrollable
[scr setContentSize:CGSizeMake(756, curXLoc)];
Finally
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
if (interfaceOrientation==UIInterfaceOrientationLandscapeLeft || interfaceOrientation==UIInterfaceOrientationLandscapeRight) {
self.scr.frame = CGRectMake(0, 0, 703,768);
} else {
self.scr.frame = CGRectMake(0, 0, 768, 1024);
}
return YES;
}
I have created a bar to appear over the keyboard for next/previous/done like the safari browser. However, the setalpha property of the UIview of the bar doesn't seem to be working. No matter what value I set it to, nothing changes. Here is the code...
here is where the create view is called..
-(void)textFieldDidBeginEditing:(UITextField *)textField{
// Call the createInputAccessoryView method we created earlier.
// By doing that we will prepare the inputAccView.
[self createInputAccessoryView];
// Now add the view as an input accessory view to the selected textfield.
[textField setInputAccessoryView:inputAccView];
// Set the active field. We' ll need that if we want to move properly
// between our textfields.
txtActiveField = textField;
}
here is where i actually create and set its values...
-(void)createInputAccessoryView{
// Create the view that will play the part of the input accessory view.
// Note that the frame width (third value in the CGRectMake method)
// should change accordingly in landscape orientation. But we don’t care
// about that now.
inputAccView = [[UIView alloc] initWithFrame:CGRectMake(10.0, 0.0, 310.0, 40.0)];
// Set the view’s background color. We’ ll set it here to gray. Use any color you want.
[inputAccView setBackgroundColor:[UIColor darkGrayColor]];
// We can play a little with transparency as well using the Alpha property. Normally
// you can leave it unchanged.
[inputAccView setAlpha: 0.1f];
... code for adding buttons and their properties
}
so basically this is all there is to it. but the setAlpha property does nothing, regardless of what I set it to. However, background color works fine. Any ideas?
Thanks
If you want it to look like the prev/next/done bar in Safari etc, create a UIToolbar with the style set to translucent black. This also has the advantage of laying out your buttons nicely, with the correct style, and auto adjusting between landscape and portrait.
Not a direct answer to your question but probably a better way of acheiving what you actually want.
out of utter curiosity try using:
UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(10.0, 0.0, 310.0, 40.0)];
overlay.backgroundColor = [UIColor blackColor];
overlay.alpha = 0.5f;
[self.view addSubview:overlay];
it's hard to tell what the issue is without being able to see how many views you have and how you've stacked them. check you've defined your "addSubview" and what the hierarchy looks like
i am doing application where i have taken two views Portrait and Landscape. i am creating a label programitically and calling it by parameter passing.As i want the position of the label to be changed in the landscapeView so i am taking two views.Instead i want to do in a SingleView
instead of using two views i want to have only one view and set the label position accordingly in portrait and landscape.
so please suggest me how to have only one view and change the textLabel position according to the view..please suggest me with sample code.
At present i am using the below code
[self.portraitView addSubview:[self createLabel:CGRectMake(450,140,60,20):#"Ratings:"]];
[self.landscapeView addSubview:[self createLabel:CGRectMake(600,140,60,20):#"Ratings:"]];
-(UILabel*)createLabel:(CGRect)frame :(NSString*)labelTitle {
UILabel *myLabel = [[UILabel alloc] initWithFrame:frame];
[UIFont fontWithName:#"Arial" size:13];
myLabel.text = labelTitle;
}
Make your UILabel *myLabel a class variable by declaring it in your .h file.
Call the createLabel method in the viewDidLoad method of your viewController based on the correct device orientation.
-(void) viewDidLoad
{
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation
if(orientation == UIDeviceOrientationPortrait)
CGRect frame = CGRectMake(450,140,60,20);
else
CGRect frame = CGRectMake(600,140,60,20);
myLabel = [[UILabel alloc] initWithFrame:frame];
[UIFont fontWithName:#"Arial" size:13];
myLabel.text = labelTitle;
}
Reset the frame in this method
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationLandScape)
{
mylabel.frame = CGRectMake(600,140,60,20); //your landscape frame
mylabel.text = #"Ratings:";
}
else
{
mylabel.frame = CGRectMake(450,140,60,20); // your portrait frame
mylabel.text = #"Ratings:";
}
}
You will need to dig around a little bit for covering all the possible orientations in this method.
Cheers!!!
in your code there is a method called
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIInterfaceOrientationLandScape)
//set label frame here
}
Implement the following two methods in your viewcontroller.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
and
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
In willRotateToInterfaceOrientation:duration: method, set the required frame to the label instance.
You should set the labels frame in the layoutSubviews method of the UILabel's superview and check the superviews bounds or the interface orientation to determine the appropriate frame for the label. If you also use autoresizingMask on the UILabel correctly, the transition will be animated nicely.
Also: why do you use two views? instead of applying different layouts to one?
I have seen this question being addressed several times here at SO, e.g Problem with UIScrollView Content Offset, but I´m still not able to solve it.
My iphone app is basically a tab bar controller with navigation bar. I have a tableview controller made programmatically and a DetailViewController that slides in when I tap a cell in my tableview controller.
The DetailViewController is made in IB and has the following hierarchy:
top view => UIScrollView => UIView => UIImage and a UITextField.
My goal is to be able to scroll the image and text field and this works well. The problem is that my UIScrollView always gets positioned at the bottom instead at the top.
After recommendations her at SO, I have made my UIScrollView same size as the top view and instead made the UIView with the max height (1500) of my variable contents.
In ViewDidLoad I set the contentSize for the UIScrollView (as this is not accessible from IB):
- (void)viewDidLoad {
[scrollView setContentSize:CGSizeMake(320, 1500)];
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
NSLog(#"viewDidLoad: contentOffset y: %f",[scrollView contentOffset].y);
}
Specifically setting the contentOffset, I would expect my scrollView to always end up at the top. Instead it always go to the bottom. It looks to me that there is some autoscrolling beyond my control taking place after this method.
My read back of the contentOffset looks OK. It looks to me that there may be some timing related issues as the scrolling result may vary whether animation is YES or NO.
A ugly workaround I have found is by using this delegate method:
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrView {
NSLog(#"Prog. scrolling ended");
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}
This brings my scrollview to top, but makes it bounce down and up like a yo-yo
Another clue might be that although my instance variables for the IBOutlet are set before I push the view controller, the first time comes up with empty image and textfield:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!detailViewController) {
detailViewController = [[DayDetailViewController alloc] init];
}
// Pass dictionary for the selected event to next controller
NSDictionary *dict = [eventsDay objectAtIndex:[indexPath row]];
// This method sets values for the image and textfield outlets
[detailViewController setEventDictionary:dict];
// Push it onto the top of the navigation controller´s stack.
[[self navigationController] pushViewController:detailViewController animated:NO];
}
If I set animation to YES, and switch the order of the IBOutlet setting and pushViewController, I can avoid the emptiness upon initialization. Why?
Any help with these matters are highly appreciated, as this is really driving me nuts!
Inspired of Ponchotg´s description of a programmatically approach, I decided to skip interface builder. The result was in some way disappointing: The same problem, with the scrollview ending up in unpredictable positions (mostly at bottom), persisted.
However, I noticed that the scroll offset error was much smaller. I think this is related to the now dynamic (and generally smaller) value of ContentOffset. After some blind experimenting I ended up setting
[textView setScrollEnabled:YES];
This was previously set to NO, as the UITextView is placed inside the scrollview, which should take care of the scrolling. (In my initial question, I have erroneously said it was a UITextField, that was wrong)
With this change my problem disappeared, I was simply not able to get into the situation with scrollview appearing at bottom anymore in the simulator! (At my 3G device I have seen a slight offset appear very seldom, but this is easily fixed with scrollViewDidEndScrollingAnimation delegate described previously ).
I consider this as solved now, but would appreciate if anyone understand why this little detail messes up things?
OK! i have a question before i can give a correct answer.
Why are you using a UIView inside the Scrollview?
You can always only put your UIImageView and UITextField inside the UIScrollView without the UIView
and set the contentSize dynamically depending on the size of the text.
to give you an example how i do it:
int contSize = 0;
imageView.frame = CGRectMake(10, 0, 300, 190);
imageView.image = [UIImage imageNamed:#"yourimage"];
contSize = 190 //or add extra space if you dont want your image and your text to be so close
[textField setScrollEnabled:NO];
textField.font = [UIFont systemFontOfSize:15];
textField.textColor = [UIColor grayColor];
textField.text = #"YOUR TEXT";
[textField setEditable:NO];
textField.frame = CGRectMake(5, contSize, 310, 34);
CGRect frameText = textField.frame;
frameText.size.height = textField.contentSize.height;
textField.frame = frameText;
contSize += (textField.contentSize.height);
[scrollView setScrollEnabled:YES];
[scrolView setContentSize:CGSizeMake(320, contSize)];
In the above example I first create an int to keep track of the ysize of my view then Give settings and the image to my UIImageView and add that number to my int then i give settings and text to my UITextField and then i calculate the size of my text depending on how long is my text and the size of my font, then add that to my int and finally assign the contentSize of my ScrollView to match my int.
That way the size of your scrollview will always match your view, and the scrollView will always be at top.
But if you don't want to do all this, you can allways just:
[scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
at the end of the code where you set your image and your text, and the NOto avoid the bouncing.
Hope this helps.
I noticed that after an orientation change from portrait to landscape, I'm not getting touchesBegan events for some parts of my view any longer. I suppose that this is because I'm not informing my UIView about the dimension change of my window's frame after the device rotation.
I'm setting up everything programmatically (UIWindow, UIViewController, UIView) like this:
myViewController = [[myUIViewController alloc] init];
myWindow = [[UIWindow alloc] initWithFrame: rect];
myView = [[myUIView alloc] initWithFrame: [myWindow bounds]];
[myViewController setView:myView];
[myWindow addSubview:myView];
[myWindow setFrame:rect];
[myWindow makeKeyAndVisible];
When I get the didRotateFromInterfaceOrientation notification, I'm updating the window frame like this:
[[[self view] window] setFrame:rect];
But after that, my UIView does no longer get touchesXXX events for all areas. It seems that only the areas of the previous frame are still reporting events. So my question: Is there anything else I need to do in didRotateFromInterfaceOrientation to inform my UIView about the dimension change?
Thanks for help!
EDIT: Do I have to reposition the UIView on didRotateFromInterfaceOrientation() or is this done automatically? I noticed that the "transform" property of my UIView is set to a transformation matrix when the orientation changes. However, this makes it very hard to reposition my view. The docs say that the "frame" property can't be used when a transformation is active, so I tried to modify the "center" property to reposition my view, but this also doesn't work correctly. I want to move the view to the top-left corner, so I set "center" to (screenwidth/2,screenheight/2) but it doesn't position the view correctly :( Any idea or info what must be done to get the events right in orientation mode?
I have had this same problem, and I believe it is a frame issue.
I had to manually set the rects depending on orientation, as well as set the userInteractionEnabled on the main view, like:
if (appOrientation == 0)
appOrientation = [UIApplication sharedApplication].statusBarOrientation;
if (appOrientation == UIInterfaceOrientationLandscapeLeft || appOrientation == UIInterfaceOrientationLandscapeRight) {
[[UIApplication sharedApplication] setStatusBarHidden:YES];
myView.frame = CGRectMake(0, 0, 1024, 768);
} else {
[[UIApplication sharedApplication] setStatusBarHidden:YES];
myView.frame = CGRectMake(0, 0, 768, 1024);
}
myView.userInteractionEnabled = YES;
OK I know this is an old question but this is how I fixed this issue.
In my situation I had a storyboard with a view that would be displayed either in portrait or forced to landscape mode depending on a user setting.
My app displays the statusBar at all times except for when I'm showing this view.
To make this all work, the transformations had to be applied in the viewWillAppear method for one. I had the following code in the viewDidAppear method at first and that messed with the bounds for the touchesBegan event I guess.
Here's the viewWillAppear code:
- (void)viewWillAppear:(BOOL)animated
{
// Hide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES];
// This is to offset the frame so that the view will take the fullscreen once the status bar is hidden
self.navigationController.navigationBar.frame = CGRectOffset(self.navigationController.navigationBar.frame, 0.0, -20.0);
// If view is to be displayed in landscape mode
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"orientation"])
{
// Change status bar orientation
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft];
// Turn the view 90 degrees
[self.navigationController.view setTransform:CGAffineTransformMakeRotation(M_PI/2)];
// Set the frame and the bounds for the view
// Please Note: Frame size has to be reversed for some reason.
[self.navigationController.view setFrame: CGRectMake(0,0,320,480)];
[self.navigationController.view setBounds: CGRectMake(0,0,480,320)];
// Make sure user can interact with view
[self.navigationController.view setUserInteractionEnabled:YES];
}
}
Any other thing that had to happen layout wise, have to happen in the viewDidAppear method. For instance I had an image that covered the whole view and the frame had to be set depending on the orientation. Setting the frame in the viewWillAppear gave weird results but the same code worked perfectly in viewDidAppear.
Hope this helps someone as I banged my head for 6 hours on this thing.