I have a iPhone app with a main view that is 480 x 510. I'm a bit confused as to how the coordinate system changes when I go from portrait to landscapeRight.
Initially, I had a 480x480 content area, and wanted to add a button on the side to bring up a menu. However, the only way I could find to have the writing run down the length of the left side of the app was to change the orientation of the whole app to landscape right.
Now, with the orientation in Landscape, the scrollview is starting at the top left, when I really want it to start at the original orientation point (from when it was in portrait mode), which would be bottom left. But I can't figure out how to change the original starting point of the scrollview. I tried contentOffset, but it doesn't seem to be working.
Another way of going about this (that I might end up doing) is forget having a title on the button, and just create a graphic for the button that has text vertically oriented.
if (self = [super initWithCoder:coder]) {
// Size of the scrollview
self.contentSize = CGSizeMake(480, 510);
[self setContentOffset:CGPointMake (0, -160)];
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = YES;
self.alwaysBounceVertical = NO;
self.alwaysBounceHorizontal = NO;
self.bounces = YES;
self.userInteractionEnabled = YES;
self.musicGridView = [[[MusicGridView alloc] initWithCoder:coder] autorelease];
// Rectangle where I put the music grid (origin is left aligned, and down 160 pixels to account for landscape view)
self.musicGridView.frame = CGRectMake(0, 160, 480, 480);
[self addSubview: musicGridView];
self.menuButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.menuButton.frame = CGRectMake(0, 480, 480, 32);
[menuButton setTitle: #"Tap to get Menu" forState: UIControlStateNormal];
[menuButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[menuButton addTarget:self action:#selector(showMenu) forControlEvents:UIControlEventTouchUpInside];
[self addSubview: menuButton];
simply set the points x,y in
//it goes in particular pont of view
[scrollview setContentOffset:CGPointMake(x,y) animated:YES];
//if x=0 in loop, increase y value scrollview move only vertical direction
[scrollview setContentOffset:CGPointMake(0,y) animated:YES];
//if y=0 in loop, increase x values scrollview move only horizontal direction
[scrollview setContentOffset:CGPointMake(x,0) animated:YES];
Andrey Tarantsov has done an awesome rundown of the various quirks of the UIScrollView class, including code for various workarounds to common problems. It might be worthwhile taking a look.
Related
I have a UIView (view B) with a UIButton on it.
I add this view B to my main view (view A) in an area outside of the bounds of the main view and I than animate it in with a UIView animation.
After the UIView animation is complete and View B is now on top of View A so the button is visible, the button does not respond to touches... I have never seen this before but this is the first app I am doing with the new iOS (iOS 5). Any ideas?
Thanks in advance.
Is this the situation you are describing? Because it seems to work fine. Did you check if userInteractionEnabled is set to YES on the UIView?
- (void)buttonPressed:(UIButton*)button
{
NSLog(#"button pressed");
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, -100, 100, 100)];
view.backgroundColor = [UIColor blackColor];
UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Button" forState:UIControlStateNormal];
button.frame = CGRectMake(0, 10, 100, 20);
[view addSubview:button];
[self.view addSubview:view];
[UIView animateWithDuration:0.5 animations:^{
view.transform = CGAffineTransformMakeTranslation(0, 100);
}];
[view release];
}
I'm not sure that this was answered so I give it a shot, just for the record:
Check that the buttons are not outside the frame of any superview.
I found that a button placed outside like this may not work. Come to think about it, this is weird. I ran into this when I was making a view with buttons that animates in from below. Underneath this I have a gray touchable view to allow cancel. Only problem was that 1) for the gray area I used the parent view itself and 2) I let this gray area shrink as the subview animated in place ... so as a result, the buttons became outside, and it didn't work.
Solution was to leave the view full size and either add another as the gray, or make the first one gray and not shrunk (the only reason I wanted to avoid this was that it would make a pile of half transparent layers which is not optimal). Then the view with buttons on top of that. :)
Hope this helps.
If you have created the Button through programming then you have to do :-
myButton.userInteractionEnabled =YES;
Hope it Helps... :)
Ok, I have been working on solving this problem all day, and I am getting really close. I am trying to have create a way to view more than one scrollView/imageView nested pair that allows for zooming on an image.
When the view loads, there is just one scrollView that takes up the whole screen, but then when a button is pressed, I cut the width of the first scrollView in half, and unhide another (which has a nested imageView in it as well) right next to it. So there is a split view effect, and ideally the user will be able to pinch and zoom each image separately.
So I have all that working except for the separate pinch and zoom part. No matter where I pinch on the screen, only the first scrollView zooms. So even though I am touching another scrollView, it is still only affecting the first.
I have them setup in IB, and then they are setup in viewDidLoad this way:
[scrollView setBackgroundColor:[UIColor blackColor]];
[scrollView setCanCancelContentTouches:NO];
scrollView.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.minimumZoomScale = 1;
scrollView.maximumZoomScale = 5;
scrollView.delegate = self;
[scrollView setScrollEnabled:YES];
imageView3 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"monitor.JPG"]];
[scrollView addSubview:imageView3];
//[scrollView setFrame:CGRectMake(0, 0, 1024, 660)];
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.minimumZoomScale = 1;
scrollView1.maximumZoomScale = 5;
scrollView1.delegate = self;
[scrollView1 setScrollEnabled:YES];
imageView31 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"monitor.JPG"]];
[scrollView1 addSubview:imageView31];
And then I hide and unhide different scrollViews (I have 40 depending on the segmentedControl index on the toolbar. Am I headed in the right direction? Is it possible to have two separately accessible scrollViews?
Any help would be appreciated.
Thanks!
EDIT:
Ok so I went through and updated the clipToBunds bit...DUH. It definitely makes it look better, but still isn't solving the problem. Here is the code I am calling depending on the selected index:
-(void) pickedOne{
if(segment.selectedSegmentIndex == 0){
[scrollView setFrame:CGRectMake(0, 0, 1024, 660)];
[scrollView setContentSize:CGSizeMake(1024, 660)];
scrollView.hidden = NO;
scrollView1.hidden = YES;
scrollView2.hidden = YES;
scrollView3.hidden = YES;
}else if(segment.selectedSegmentIndex == 1){
[scrollView setFrame:CGRectMake(0, 0, 512, 660)];
scrollView.zoomScale = 1.0;
scrollView.hidden = NO;
[scrollView1 setFrame:CGRectMake(512, 0, 512, 660)];
scrollView1.zoomScale = 1.0;
scrollView1.hidden = NO;
scrollView2.hidden = YES;
scrollView3.hidden = YES;
}
Is there anything majorly wrong with that approach?
If I pinch to zoom on the right scrollView, it makes the scroll view bigger, (but doesn't increase the size of the scrollView2 image) but it DOES increase the size of the first scrollView's image when you pinch inside of EITHER scrollViews...strange
scrollView.clipsToBounds = NO; // default is NO, we want to restrict drawing within our scrollview
Isn't this the opposite of what you want? Setting it to YES restricts restricts drawing to within your scrollview.
It sounds to me like you aren't resizing the scrollview. Are you resizing its contents or the image view within it? Can you post the code that is called when you tap the button?
Ok I have been working on this feature for some time now and it is driving me nuts. I have looked all around the web and can't seem to find any answer. I want to have a view that has two UIScrollviews, that themselves contain a UIImageView each. So I can have to images on my view that are SEPARATELY scroll/zoomable.
It seems pretty simple, but I just can't get it to work. I setup the ScrollView/ImageView pairs in IB and hooked them up ok. Now my viewDidLoad code looks like this:
-(void) viewDidLoad
{
// set the image to be displayed, pic your own image here
imageView = [[MyImage alloc] initWithImage: [UIImage imageNamed: #"newBackground.png"]];
// yes we want to allow user interaction
[imageView setUserInteractionEnabled:YES];
// set the instance of our myScrollView to use the main screen
scrollView = [[MyScroll alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
// turn on scrolling
[scrollView setScrollEnabled: YES];
// set the content size to the size of the image
[scrollView setContentSize: imageView.image.size];
// add the instance of our myImageView class to the content view
[scrollView addSubview: imageView];
// flush the item
[imageView release];
// set max zoom to what suits you
[scrollView setMaximumZoomScale:1.0f];
// set min zoom to what suits you
[scrollView setMinimumZoomScale:0.25f];
// set the delegate
[scrollView setDelegate: self];
// scroll a portion of image into view (my image is very big) :)
//[scrollView scrollRectToVisible:CGRectMake(100, 100, 320, 440) animated:NO];
// yes to autoresize
scrollView.autoresizesSubviews = YES;
// set the mask
scrollView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
// set the view
//self.view =scrollView;
[scrollView setFrame:CGRectMake(0, 0, 320, 240)];
self.view =scrollView;
imageView1 = [[MyImage alloc] initWithImage: [UIImage imageNamed: #"newBackground.png"]];
// yes we want to allow user interaction
[imageView1 setUserInteractionEnabled:YES];
// set the instance of our myScrollView to use the main screen
scrollView1 = [[MyScroll alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
// turn on scrolling
[scrollView1 setScrollEnabled: YES];
// set the content size to the size of the image
[scrollView1 setContentSize: imageView1.image.size];
// add the instance of our myImageView class to the content view
[scrollView1 addSubview: imageView1];
// flush the item
[imageView1 release];
// set max zoom to what suits you
[scrollView1 setMaximumZoomScale:1.0f];
// set min zoom to what suits you
[scrollView1 setMinimumZoomScale:0.25f];
// set the delegate
[scrollView1 setDelegate: self];
// scroll a portion of image into view (my image is very big) :)
//[scrollView scrollRectToVisible:CGRectMake(100, 100, 320, 440) animated:NO];
// yes to autoresize
scrollView1.autoresizesSubviews = YES;
// set the mask
scrollView1.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
// set the view
//self.view =scrollView;
[scrollView1 setFrame:CGRectMake(0, 300, 320, 220)];
//I do this only because I don't know what else to do. This effectively adds the scrollview to the scrollview...
self.view =scrollView1;
And the first scrollView loads, but then the second one is nested in that one! I tried doing[self.view addSubView:scrollView1]; but that just made the app crash. I'm trying my best to really dig in and figure out scrollViews as best I can, but I am just getting owned here.
Please help!
Thanks
** To further clarify, all I want is to have a scrollView on the top half of an image that can pan and zoom with an image inside of it, and then another scrollView separate from the firt that can pan and zoom on the bottom half of the screen, independent of the first.**
You need to add both scroll views as subviews of the ViewController's view (self.view):
[self.view addSubview:scrollView];
[self.view addSubview:scrollView1];
You'll then need to manually position those views so they're positioned like you want them (the above code will put the two scroll views on top of each other, with some arbitrary default size which may or may not be what you want).
I'm using a UIView to control the layout of my view (along with a view controller). I want UIScrollView to only use half of the vertical screen. That works fine if I use the upper half of the screen, but not the bottom half.
Here's the relevant code from the UIViewController:
- (void)loadView {
CGRect fullFrame = [[UIScreen mainScreen] applicationFrame];
//trying to put the scroll view on the bottom half of the screen, but does not work.
CGRect halfFrame = CGRectMake(0, fullFrame.size.height / 2 ,
fullFrame.size.width, fullFrame.size.height / 2);
//use this instead for the scroll view to go to the top half of the screen (and work properly)
//CGRect halfFrame = CGRectMake(0, 0 , fullFrame.size.width, fullFrame.size.height / 2);
UIScrollView* sv = [[UIScrollView alloc] initWithFrame:halfFrame];
[sv setContentSize:CGSizeMake(3 * halfFrame.size.width, halfFrame.size.height)];
CGRect stencilFrame = halfFrame;
UIView *leftView = [[UIView alloc] initWithFrame:stencilFrame];
stencilFrame.origin.x += stencilFrame.size.width;
UIView *centerView = [[UIView alloc] initWithFrame:stencilFrame];
stencilFrame.origin.x += stencilFrame.size.width;
UIView *rightView = [[UIView alloc] initWithFrame:stencilFrame];
//mix up the colors
[leftView setBackgroundColor:[UIColor redColor]];
[centerView setBackgroundColor:[UIColor greenColor]];
[rightView setBackgroundColor:[UIColor blueColor]];
//add them to the scroll view
[sv addSubview:leftView];
[sv addSubview:centerView];
[sv addSubview:rightView];
//turn on paging
[sv setPagingEnabled:YES];
UIView *containerView = [[UIView alloc]initWithFrame:fullFrame];
[containerView addSubview:sv];
[self setView:containerView];
}
Thank you in advance for any advice or help.
I figured it out. The crux of the problem is that views within the scroll view are initialized with the same frame as the scroll view itself. When the scrollView is initialized with halfFrame, the origin is (0, half the full screen size), which is ok since that is relative to the application window itself. However, the views that are put inside the scrollView (like leftView) are initialized to halfFrame, but in this case the origin is relative to the scrollView, effectively placing them off the screen. Setting the origin to (0,0) fixes this:
CGRect stencilFrame = CGRectMake(0, 0, fullFrame.size.width , fullFrame.size.height / 2);
contentSize must contain the rectangle of the view inside the scroll view. That is, the total size of all scrollable controls within. The frame of the UIScrollView decides how much scrolling is needed to let the user browse everything.
You don't have the "full frame" available if you have a nav bar or a tab bar. In general, code that uses [UIScreen mainScreen] for layout information is probably wrong.
Additionally, the status bar can change size if (for example) a call is in progress or tethering is enabled.
Instead, use any sane value for full frame and enable autoresizing:
CGRect fullFrame = {{0,0}, {320,480}};
...
sv.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
EDIT: You also probably need to subclass UIScrollView and implement -setFrame: so that it also sets the content size and -layoutSubviews to do the correct layout.
I would like to implement a view (it will actually be going into the footer of a UITableView) that implements 1-3 buttons. I would like the layout of these buttons (and the size of the buttons themselves) to change depending on which ones are showing. An example of almost the exact behavior I would want is at the bottom of the Info screen in the Contacts application when you are looking at a specific contact ("Add to Favorites" disappears when it is clicked, and the other buttons expand to take up the available space in a nice animation).
As I'm running through the different layout scenarios, I'm hard coding all these values and I just think... "this is NOT the way I'm supposed to be doing this."
It even APPEARS that Interface Builder has some features that may do this for me in the ruler tab, but I'll be darned if I can figure out how they work (if they work) on the phone.
Does anyone have any suggestions, or a tutorial online that I could look at to point me in the right direction?
Thanks much.
You could take a look at
Stanford cs193p classes
I think there is a demo in one of the lessons/example where they programaticaly set the autoresize of the buttons and some other where they animate the view.
you can also make the view set dynamically the width of each of its subview to (ownWidth/numberofSubView),the same for the positon of each elements.
[edit] like that ? it's not "dynamic" yet, but you've got the idea
you can increase/decrease numberOfbuttons when "adding/removing" a button then reset the new frame of all the subviews
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
view.backgroundColor = [UIColor lightGrayColor];
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
int numberOfbuttons = 2;
CGFloat buttonsLegth = (-20+view.bounds.size.width)/numberOfbuttons-20;
for(int i=0;i<numberOfbuttons;i++){
CGRect buttonFrame = CGRectMake(0, 0, buttonsLegth, 37);
buttonFrame.origin.x = (buttonFrame.size.width+20)*i + 20.0;
buttonFrame.origin.y = 20.0;
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // Autoreleased
button.frame = buttonFrame;
[button setTitle:#"Done" forState:UIControlStateNormal];
[view addSubview:button];
}
self.view = view;
[view release];
}
hi remove all buttons in view and add again using this method...
you have to pass number of buttons and a UIView in which you want to add these buttons
-(void)addButtons:(int)numberOfButtons ToView:(UIView *)containerView;
{
CGRect containerRect = containerView.frame;
CGFloat padding = 5.0;
CGFloat width = (containerRect.size.width - (padding*numberOfButtons+1))/numberOfButtons;
for (int i = 1; i<=numberOfButtons; i++)
{
UIButton * btn = [[[UIButton alloc] initWithFrame:CGRectMake(i*padding+width, 0, width, containerRect.size.height)]autorelease];
//set Button Properties like Target,backColor,Title,,,,etc MUST SET TAG TO ACCESS THEM IN CLICK METHOD IF YOU ARE USING SAME SELECTOR FOR ALL BUTTONS.
[containerView addSubview:btn];
}
}
Try this and have fun......