I have a UIDatepicker where i have added border image so that it sits on top of UIDatepicker border . In simulator the border image is in exactly on top of UIDatepicker border ,but when i run the project on iphone / ipod device .the border image tends to be in out of position .Why is this happening ?
When i tap on settingsButton ..settingsButtonChanged method is called and in settingsView datepicker is added .
Thanks
UPDATE :
-(void)viewDidLoad
{
userTimePicker = [[UIDatePicker alloc]init
}
-(IBAction)settingsButtonChanged:(UIButton *)sender
{
UIImageView *settingsImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"settingsViewImage.png"]];
settingsImage.frame = CGRectMake(0.0, 0.0, 280.0, 370.0);
CGFloat height = [UIScreen mainScreen].bounds.size.height;
if(height==568.00)
{
settingsView.frame = CGRectMake(0.0, 50.0, 280.0, 370.0);
}else
{
settingsView.frame = CGRectMake(20.0, 45.0, 280.0, 370.0);
}
settingsView.backgroundColor = [UIColor clearColor];
[settingsView addSubview:settingsImage];
UIImageView *userTimePickerBorder = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"datepickerBorder.png"]];
userTimePickerBorder.frame = CGRectMake(0.0, 0.0, 150.0, 180.0);
userTimePicker.frame = CGRectMake(65.0, 165.0, 150.0, 180.0);
userTimePicker.datePickerMode = UIDatePickerModeTime;
[settingsView addSubview:userTimePicker];
[userTimePicker addSubview:userTimePickerBorder];
[symptomView addSubview:settingsView];
}
Suggestion 1
Well, first of all, this code makes no sense at all:
- (void)viewDidLoad {
userTimePicker = [[UIDatePicker alloc]init];
}
Consider what that does. Suppose you have a property or instance variable called userTimePicker (you must have something like that, right?). Now, either it is an outlet pointing to an actual date picker coming from the nib/storyboard, or it isn't. Well then:
If it is, now it isn't! You've just overwritten the reference to the actual date picker in the interface with a different date picker.
If it isn't, you've just set userTimePicker to a date picker, but that date picker is not in the interface (you have no code adding it to the interface).
So, either way, from now on, userTimePicker is useless; it does not point to anything in the interface.
So you would certainly need to fix that before doing anything else!
Suggestion 2
Also, I have a suggestion for why your results on the simulator differ from your results on the device: it might be because you've been testing repeatedly on the simulator. This can cause old code/resources to be present in the simulator version of your app. To fix that, clean out your caches and restore the simulator to its defaults, as I describe here: https://stackoverflow.com/a/6247073/341994 I'm hoping that will at least cause the simulator and the device to behave the same! And then you can get on with the real business of fixing your code.
Suggestion 3
This code is really weird:
CGFloat height = [UIScreen mainScreen].bounds.size.height;
if(height==568.00)
{
settingsView.frame = CGRectMake(0.0, 50.0, 280.0, 370.0);
}else
{
settingsView.frame = CGRectMake(20.0, 45.0, 280.0, 370.0);
}
You should not be consulting the screen bounds for anything! All of this should be taking place within some view controller. The view controller's view should rotate and resize to fit the device orientation or screen size, so the bounds of the view controller's view will change, and that is what you should should be checking.
And instead of hard-coding those frame values, you should express them in terms of the view controller view's bounds, or the bounds of the superview they are to go into. That will give you consistent results. Even better, if this is on iOS 6, use constraints instead of setting frames.
Related
I want to show completely custom buttons in UINavigationController's UIToolbar, and support portrait and landscape. Currently I have implemented a RotatingButton (a UIView subclass) class, which contains one UIButton that fills the whole RotatingButton frame. A RotatingButton also contains two images, for portrait and landscape orientations, and the heights of these images differ. Then this RotatingButton gets wrapped into UIBarButtonItem as a custom view.
Currently, in RotatingButton's layoutSubviews, I am setting the whole view's bounds, and setting the button the appropriate image for the current orientation. This works well and handles rotations as desired.
- (void) createLayout {
[self addButtonIfNeeded];
UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
if(UIInterfaceOrientationIsLandscape(currentOrientation)) {
[self.button setImage:self.landscapeImage forState:UIControlStateNormal];
self.button.frame = CGRectMake(0.0, 0.0, self.landscapeImage.size.width / 2, self.landscapeImage.size.height / 2);
self.bounds = CGRectMake(0.0, 0.0, self.landscapeImage.size.width / 2, self.landscapeImage.size.height / 2);
} else {
[self.button setImage:self.portraitImage forState:UIControlStateNormal];
self.button.frame = CGRectMake(0.0, 0.0, self.portraitImage.size.width / 2, self.portraitImage.size.height / 2);
self.bounds = CGRectMake(0.0, 0.0, self.portraitImage.size.width / 2, self.portraitImage.size.height / 2);
}
}
- (void) layoutSubviews {
[super layoutSubviews];
[self createLayout];
}
However, this problem remains:
Starting view at portrait orientation
Push a view controller onto stack
Rotate the device to landscape (the current view reacts appropriately)
Pop the last view controller: the previous view reacts otherwise well, but the RotatingButtons' layoutSubviews don't get called, and the buttons remain larger than they should.
So, currently after popping a view controller, the previous UIBarButtonItems don't have their layoutSubviews called, and they remain too large (or too small, if we start from landscape and rotate to portrait in another view). How to solve this problem?
This is a really tricky question. You should try overriding viewWillAppear: to call [self.view setNeedsLayout] to force a layout update whenever the view is about to appear.
I didn't find a completely satisfactory solution, but my buttons happened to be of suitable size, and this kind of a solution worked very well for me:
UIBarButtonItem* b = [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:target action:selector];
UIImage *barButton = [portraitImage resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];
UIImage *barButton_land = [landscapeImage resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];
[b setBackgroundImage:barButton forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[b setBackgroundImage:barButton_land forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
And then obviously adding the created button as rightBarButtonItem/leftBarButtonItem, or as you may want to use it.
The problem with this is that if your buttons are not wide enough, the buttons may look completely wrong (since the middle content of the image is tiled in this solution).
I'm a beginner in iOS programming and I'm looking for an answer to my question.
I have a UISlider inside a UITableViewCell and I'm trying to get this disposition: Label-Slider-DetailLabel(dynamic).
This is my code :
cell = [tableView dequeueReusableCellWithIdentifier:#"SelectedMeetingCell"];
[cell.textLabel setText:#"Duration"];
[cell.detailTextLabel setText:[Utilities StringFromDuration:Agenda.InitialDuration.doubleValue]];
sliderCell = (SliderCell*)[[UIViewController alloc] initWithNibName:#"SliderCell" bundle:nil].view;
[sliderCell setDelegate:self];
[sliderCell.slider setValue:Agenda.InitialDuration.doubleValue];
[cell.contentView addSubview:sliderCell];
sliderCell.slider.frame = CGRectMake(100, 0, 500, 44);
The last line is the way I used to place my slider the way I wanted to be. It works great for iPad but not at all for the iPhone version. Is there any way to resize the width of my slider automatically depending on the device ?
(SliderCell is a UITableViewCell with a UISlider #property)
Thank you all in advance!
Instead of hard coding the values, you could get the container views width and set the sliders width as a percentage of it.
CGRect superViewFrame = slider.superView.frame;
CGRect sliderFrame = slider.frame;
sliderFrame.size.width = <your choice for eg, superViewFrame.size.width * 0.3f>
sliderFrame.origin.x = <your choice for eg, superViewFrame.size.width * .2f>
slider.frame = sliderFrame;
you can get the size of a device by calling self.view
sliderCell.slider.frame = CGRectMake(100, 0, self.view.frame.size.width, self.view.frame.size. height);
after you may want to subtract or divide depending on your view's size
Trying to get UIButtons to decrease height but maintain width when device is rotated.
Here's code from initWithFrame: of the view that contains the buttons.
ParentView.m
self = [super initWithFrame:CGRectMake(0, 0, UIKeyboardPortraitHeightPhone, 320)];
self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
self.autoresizesSubviews = YES;
// And then on each button I call
myButton.frame = myFrame;
myButton.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin);
The problem: Before I even rotate the device, the buttons have resized and gotten smaller (in height) than the frame I initialized them to.
Previous research: It looks like I'm having the same problem as this person: Cannot get UIButton autoresizingMask to work, but I followed the advice and got the same unsatisfactory result.
I also looked at the apple docs, which say that the autoresizing mask is only supposed to take effect when the bounds of the parent view change. Obviously either the bounds of my parent view are changing without me realizing it, or something else fishy is going on here.
Any ideas as to what could be the problem?
I have some code that creates a table cell with a slider. It's pretty straightforward and it sizes well on the iPhone. I've anonymized it a bit here:
UITableViewCell* cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foo"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
CGRect contentViewFrame = cell.contentView.frame;
CGRect sliderFrame = CGRectMake(10, 0, 280, contentViewFrame.size.height);
UISlider* slider = [[UISlider alloc] initWithFrame:sliderFrame];
UIImage* minimumImage = [UIImage imageNamed:#"min.png"];
UIImage* maximumImage = [UIImage imageNamed:#"max.png"];
slider.minimumValueImage = minimumImage;
slider.maximumValueImage = maximumImage;
slider.value = 0.5f;
[slider addTarget:self action:#selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:slider];
[slider release];
Of course, this is incorrectly sized for the iPad. So my first thought was to set the autoresizingMask property to UIViewAutoresizingFlexibleWidth. Problem solved, right? Nope. Now on the iPhone, the width of the slider-plus-images content is less than 280 and so it doesn't go right to the end -- it ends up about 20 pixels short.
On the iPad, the same thing -- the width of the UISlider automatically resizes to about 20 pixels short of the end of the cell.
Perhaps the auto resize flag is paying attention to the non-existent accessoryView of the cell? I tried setting it to nil explicitly, but I think it's nil by default, so nothing changed.
I'd like this cell's content to resize automatically to be the "full" width of the cell, regardless of device and orientation. Is there an easy way to do this?
It works exactly how you described. I am inclined to think it's iOS bug. On iPAD when you create new UITableViewCell its width set for 320. hardcoded(!) both view and contentView. It does not resize properly if set to UIViewAutoresizingFlexibleWidth. I had it set to view.frame.size.width/2 with funny results: on iPhone it's 160, on iPad it's 608!!!
I ended up manually resizing my cells and their content.
Bit late but i found the solution of the same question today, but you need to create a custom UITableViewCell.
Then you can overwrite the function
- (void) layoutSubviews
{
[dateLabel setFrame:CGRectMake(10.f, 16.f, 80.f, 12.f)];
[textLabel setFrame:CGRectMake(106.f, 16.f, contentView.frame.size.width-105.f + 1.f, 12.f)];
}
In that function the self.frame.size.width is the actual one.
And it works with rotation of the device, too.
You should be able to tell the resizing system to "stick" the object a fixed distance from the right edge (where it's not resizing far enough). If you experiment with IB you can create a view that resizes in width and is fixed to the right side.
Do you have UIViewAutoresizingFlexibleRightMargin set as well?
Set your cell's contentMode to UIViewContentModeRedraw.
UIScrollView in paging mode assumes the pages are located right next to each other, with no gap. However if you open a photo in the Photos app and swipe through photos, you can see that it has some gap between pages. I want these gaps too.
I'm looking for existing solutions if any, or for some more bizarre ideas about implementing the page gaps besides the one I have explained below. Or maybe there's some obvious easy way I am missing?
To be clear: I want the gap to only be visible while scrolling, so I cannot simply inset the page content.
My plan is to try moving the page content from inside scrollViewDidScroll callback, so that (assuming you're scrolling to the right) initially the target page is slightly offset to the right of its page boundaries, and by the time you arrive at the target page it's back at its proper location, and the source page is slightly offset to the left of its boundaries. (Or maybe instead of moving things continuously, I'll be better off shifting the offsets, say, exactly halfway between pages.)
I'm the author of the ScrollingMadness article+example that I've been referring some people to here. I've implemented progammatic zooming, and got in-photo zooming+scrolling working together with inter-photo paging. So I know how to play with UIScrollView, and am looking for the advanced stuff.
Please don't point me at TTScrollView. I've already pointed many people to it myself, but I consider it's feel too far from the native UIScrollView behaviour, and do not want to use it in my projects.
Note that this answer is quite old. The basic concept still works but
you should not be hard coding view sizes in iOS7 and 8. Even if you ignore
that advice, you should not use 480 or 330.
Have you tried making the frame of the UIScrollView slightly larger than the screen (assuming that you want to display your images fullscreen and then arranging your subviews on the same slightly-larger-than-the-screen boundaries.
#define kViewFrameWidth 330; // i.e. more than 320
CGRect scrollFrame;
scrollFrame.origin.x = 0;
scrollFrame.origin.y = 0;
scrollFrame.size.width = kViewFrameWidth;
scrollFrame.size.height = 480;
UIScrollView* myScrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
myScrollView.bounces = YES;
myScrollView.pagingEnabled = YES;
myScrollView.backgroundColor = [UIColor redColor];
UIImage* leftImage = [UIImage imageNamed:#"ScrollTestImageL.png"];
UIImageView* leftView = [[UIImageView alloc] initWithImage:leftImage];
leftView.backgroundColor = [UIColor whiteColor];
leftView.frame = CGRectMake(0,0,320,480);
UIImage* rightImage = [UIImage imageNamed:#"ScrollTestImageR.png"];
UIImageView* rightView = [[UIImageView alloc] initWithImage:rightImage];
rightView.backgroundColor = [UIColor blackColor];
rightView.frame = CGRectMake(kViewFrameWidth * 2,0,320,480);
UIImage* centerImage = [UIImage imageNamed:#"ScrollTestImageC.png"];
UIImageView* centerView = [[UIImageView alloc] initWithImage:centerImage];
centerView.backgroundColor = [UIColor grayColor];
centerView.frame = CGRectMake(kViewFrameWidth,0,320,480);
[myScrollView addSubview:leftView];
[myScrollView addSubview:rightView];
[myScrollView addSubview:centerView];
[myScrollView setContentSize:CGSizeMake(kViewFrameWidth * 3, 480)];
[myScrollView setContentOffset:CGPointMake(kViewFrameWidth, 0)];
[leftView release];
[rightView release];
[centerView release];
Apologies if this doesn't compile, I tested it in a landscape app and hand edited it back to portrait. I'm sure you get the idea though. It relies on the superview clipping which for a full screen view will always be the case.
So I don't have enough "rep" to post a comment on the answer above. That answer is correct, but there is a BIG issue to be aware of:
If you're using a UIScrollView in a viewController that's part of a UINavigationController, the navigation controller WILL resize the frame of your scrollView.
That is, you have an app that uses a UINavigationController to switch between different views. You push a viewController that has a scrollView and you create this scrollView in the viewController's -init method. You assign it a frame of (0, 0, 340, 480).
Now, go to your viewController's -viewDidAppear method, get the frame of the scrollView you created. You'll find that the width has been reduced to 320 pixels. As such, paging won't work correctly. You'll expect the scrollView to move 340 pixels but it will, instead, move 320.
UINavigationController is a bit notorious for messing with subviews. It moves them and resizes them to accommodate the navigation bar. In short, it's not a team player -- especially in this case. Other places on the web suggest that you not use UINavigationController if you need precise control over your views' size and locations. They suggest that, instead, you create your own navigationController class based on UINavigationBar.
Well that's a ton of work. Fortunately, there's an easier solution: set the frame of the scrollView in your viewController's -viewDidAppear method. At this point, UINavigationController is done messing with the frame, so you can reset it to what it should be and the scrollView will behave properly.
This is relevant for OS 3.0. I have not tested 3.1 or 2.2.1. I've also filed a bug report with Apple suggesting that they modify UINavigationController with a BOOL such as "-shouldAutoarrangeSubviews" so that we can make that class keep its grubby hands off subviews.
Until that comes along, the fix above will give you gaps in a paginated UIScrollView within a UINavigationController.
Apple has released the 2010 WWDC session videos to all members of the iphone developer program. One of the topics discussed is how they created the photos app!!! They build a very similar app step by step and have made all the code available for free.
It does not use private api either. Here is a link to the sample code download. You will probably need to login to gain access.
http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645
And, here is a link to the iTunes WWDC page:
http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj
The way to do this is like you said, a combination of a few things.
If you want a gap of 20px between your images, you need to:
First, expand your scroll view's total width by 20px and move it left by 10px.
Second, when you lay out the xLoc of your images, add 20px for each image so they're spaced 20px apart.
Third, set the initial xLoc of your images to 10px instead of 0px.
Fourth, make sure you set the content size of your scroll view to add 20px for each image. So if you have kNumImages images and each is kScrollObjWidth, then you go like this:
[scrollView setContentSize:CGSizeMake((kNumImages * (kScrollObjWidth+20)), kScrollObjHeight)];
It should work after that!
This is just a hunch, so apologies if completely wrong, but is it possible that the contentSize is just set to slightly wider than the screen width.
The correct information is then rendered within the view to the screen width and UIScrollView takes care of the rest ?
Maybe you want to try UIScrollView's contentInset property?
myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10.0);
I just thought I'd add here for posterity the solution I ended up going with. For a long time I've been using Bryan's solution of adjusting the frame in -viewDidAppear, and this has worked brilliantly. However since iOS introduced multitasking I've been running into a problem where the scroll view frame gets changed when the app resumes from the background. In this case, -viewDidAppear was not being called and I couldn't find a delegate method that would be called at the right time to reverse the change. So I decided to make my scroll view a subview of my View Controller's view, and this seemed to fix the problem. This also has the advantage of not needing to use -viewDidAppear to change the frame - you can do it right after you create the scroll view. My question here has the details, but I'll post them here as well:
CGRect frame = CGRectMake(0, 0, 320, 460);
scrollView = [[UIScrollView alloc] initWithFrame:frame];
// I do some things with frame here
CGRect f = scrollView.frame;
f.size.width += PADDING; // PADDING is defined as 20 elsewhere
scrollView.frame = f;
[self.view addSubview:scrollView];
To avoid messing with UIScrollView's frame, you could subclass UIScrollView and override layoutSubviews to apply an offset to each page.
The idea is based on the following observations:
When zoomScale !=1, the offset is zero when it is at the left / right edge
When zoomScale ==1, the offset is zero when it is at the visible rect centre
Then the following code is derived:
- (void) layoutSubviews
{
[super layoutSubviews];
// Find a reference point to calculate the offset:
CGRect bounds = self.bounds;
CGFloat pageGap = 8.f;
CGSize pageSize = bounds.size;
CGFloat pageWidth = pageSize.width;
CGFloat halfPageWidth = pageWidth / 2.f;
CGFloat scale = self.zoomScale;
CGRect visibleRect = CGRectMake(bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale);
CGFloat totalWidth = [self contentSize].width / scale;
CGFloat scrollWidth = totalWidth - visibleRect.size.width;
CGFloat scrollX = CGRectGetMidX(visibleRect) - visibleRect.size.width / 2.f;
CGFloat scrollPercentage = scrollX / scrollWidth;
CGFloat referencePoint = (totalWidth - pageWidth) * scrollPercentage + halfPageWidth;
// (use your own way to get all visible pages, each page is assumed to be inside a common container)
NSArray * visiblePages = [self visiblePages];
// Layout each visible page:
for (UIView * view in visiblePages)
{
NSInteger pageIndex = [self pageIndexForView:view]; // (use your own way to get the page index)
// make a gap between pages
CGFloat actualPageCenter = pageWidth * pageIndex + halfPageWidth;
CGFloat distanceFromRefPoint = actualPageCenter - referencePoint;
CGFloat numOfPageFromRefPoint = distanceFromRefPoint / pageWidth;
CGFloat offset = numOfPageFromRefPoint * pageGap;
CGFloat pageLeft = actualPageCenter - halfPageWidth + offset;
view.frame = CGRectMake(pageLeft, 0.f, pageSize.width, pageSize.height);
}
}