I have a UITableView with one of the UITableViewCells containing a UIScrollView and a UIPageControl; so that the user can scroll horizontally through two pages whilst browsing the table.
My problem is this- initially the page control works fine, I can see the little dots moving as expected as I browse through the pages in the scroll view. However, when I scroll the table up or down, the page control always resets back to the first page.
This is because my method which determines the page, uses the scrollview.contentoffset.x to work out which page I'm on, and the contentoffset.x ALWAYS returns 0 as soon as I start moving the table up or down. The actual scrollview itself physically does not move left or right (the content stays on the correct page); so I'm not sure why the contentoffset.x is always resetting to 0?
Here is my code in cellForRowAtIndexPath
UIScrollView* previewScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, tideRowHeight)];
[previewScrollView setContentSize:CGSizeMake(640, tideRowHeight)];
[previewScrollView setPagingEnabled:YES];
[previewScrollView setTag:0022];
[previewScrollView setShowsHorizontalScrollIndicator:NO];
[previewScrollView setDelegate:self];
[previewScrollView addSubview:todayTidesTime];
[previewScrollView addSubview:todayTidesHeight];
[previewScrollView addSubview:todayTidesHL];
[[cell contentView] addSubview:previewScrollView];
UIPageControl *tidesPageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 130, cell.frame.size.width, 10)];
[tidesPageControl setNumberOfPages:2];
[tidesPageControl setCurrentPageIndicatorTintColor:[UIColor blackColor]];
[tidesPageControl setPageIndicatorTintColor:[UIColor grayColor]];
[[cell contentView] addSubview:tidesPageControl];
self.pageControl = tidesPageControl;
Here is my code which determines the current page I'm on:
(void)scrollViewDidScroll:(UIScrollView *)sender {
CGFloat pageWidth = sender.frame.size.width;
int page = floor((sender.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
NSLog(#"content offset x %f", sender.contentOffset.x);
NSLog(#"scroll view did scroll %d", page);
self.pageControl.currentPage = page;
}
The logs output the following when I scroll the UITableView up or down (whilst the page control is on the 2nd page):
2013-10-17 21:47:36.238 Vic [61180:a0b] content offset x 319.500000
2013-10-17 21:47:36.238 Vic [61180:a0b] page we are on 1
2013-10-17 21:47:36.254 Vic [61180:a0b] content offset x 320.000000
2013-10-17 21:47:36.254 Vic [61180:a0b] page we are on 1
2013-10-17 21:47:40.173 Vic [61180:a0b] content offset x 0.000000 <------scroll up here!
2013-10-17 21:47:40.173 Vic [61180:a0b] page we are on 0 <------ my problem!
2013-10-17 21:47:40.189 Vic [61180:a0b] content offset x 0.000000
Why would the contentoffset.x be resetting to zero?
Worked it out; since I have a UIScrollView AND a UITableView together, and UITableView inherits from UIScrollView, both the table and scrollview are calling my scrollViewDidScroll method. So checking the class name of the sender parameter to scrollViewDidScroll fixes the problem- If its being called from the table (ie sender is a UITableView), do nothing. Otherwise if it's a UIScrollView, then check the page control etc.
Related
I have scroll view with label and a table view and a button . I just want to scroll the scrollview and the table view must display all the contents but tableview must not scroll. Below the tableview i have a button. How to set the frame of the button so it comes exactly below the table?
Thanks
Maybe you would like to set the YourTableView.userInteractionEnabled = NO?
Yes we can disable the scrolling the tableview.
Goto->xib->select table->Goto 1st tab->unselect the scrolling Enabled.
The answer for your Second Question.
Put the UiView in footer of your table and then place the button in that UIView you want to show in bottom.
It will always show at the bottom.
If you want to place button programmatically use following code in viewDidload method.
///--------Table Footer is Set here
UIView *footer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 260, 44)];
UIButton *adddays = [[UIButton alloc] initWithFrame:CGRectMake(10, 0, 260, 44)];
[adddays setBackgroundImage:[UIImage imageNamed:#"abcd.png"] forState:UIControlStateNormal];
[adddays addTarget:self action:#selector(buttonaction) forControlEvents:UIControlEventTouchDown];
UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(75, 12, 250, 20)];
[text setBackgroundColor:CLEAR_COLOR];
[text setText:#"Title for your button"];
[text setTextColor:XDARK_BLUE];
text.font=[UIFont fontWithName:#"Arial-BoldMT" size:18.0f];
[footer addSubview:adddays];
[footer addSubview:text];
[table setTableFooterView:footer];
This is assuming you have created IBOutlets for your scrollView, tableView and button, and hooked them up appropriately.
I find it useful to remember that we're only messing with the y-values of a CGRect (origin.y & size.height) - The x-values should be set up in the xib.
I've commented this profusely to illustrate my point better, usually I would only comment where appropriate
-(void)viewDidLoad {
[self.tableView setScrollEnabled:NO];
// Get the number of rows in your table, I use the method
// 'tableView:numberOfRowsInSection:' because I only have one section.
int numOfRows = [self.tableView numberOfRowsInSection:0];
// Get the height of your rows. You can use the magic
// number 46 (44 without including the separator
// between rows) for the height of your rows, but because
// I was using a custom cell, I had to declare an instance
// of that cell and exctract the height from
// cell.frame.size.height (adding +2 to compensate for
// the separator). But for the purpose of this demonstration
// I'm going to stick with a magic number
int rowHeight = 46; //Eww, Magic numbers! :/
// Get a reference to the tableViews frame, and set the height
// of this frame to be the sum of all your rows
CGRect frame = self.tableView.frame;
frame.size.height = numOfRows * rowHeight;
// Now we have a frame with the exact size of our table,
// so set the 'tableView.frame' AND the 'tableView.contentSize'
// to that. (Because we want ALL rows visible as you
// disabled scrolling for the 'tableView')
self.tableView.frame = frame;
self.tableView.contentSize = frame.size;
// Now we want to set up the button beneath the table.
// We still have the 'frame' variable, which gives us
// the tableView's Y-origin and height. We just add these
// two together (with +20 for padding) to get the origin of the button
CGRect buttonFrame = self.button.frame;
buttonFrame.origin.y = frame.origin.y + frame.size.height + 20;
self.button.frame = buttonFrame;
// Finally, we want the `scrollView`'s `contentSize` to
// encompass this entire setup (+20 for padding again)
CGRect scrollFrame = self.scrollView.frame;
scrollFrame.size.height = buttonFrame.origin.y + buttonFrame.size.height = 20;
self.scrollView.contentSize = scrollFrame.size;
}
You could stop the scrolling the table view. But you shouldn't be adding a tableview inside a scrollview. UITableView is subclass of UIScrollView and adding one scrollView on another will create problem. I suggest you to remove the scrollview and use the tableview alone ( as the tableview itself is a scrollview).
I am trying to create a new button of a specific size in a UIView. As it happens, this view will be used in a tableViewCell, like this.
UIImageCtrlBtnView *newView = [self initImageCtrlBtnsInViewWithHeight: 50 withWidth : 280];
[cell.contentView addSubview:newView];
I create a new view and a bunch of buttons in the method initImageCtrlBtnsInViewWithHeight.
-(UIView*) initImageCtrlBtnsInViewWithHeight: (CGFloat) rowHeight withWidth: (CGFloat) rowWidth {
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, rowWidth, rowHeight)];
newView.tag = kImageCtrlBtnViewTag;
newView.clipsToBounds = YES;
// finding the right size of the button by setting the button size to some fraction
// of the view size.
CGRect largeButtonFrame = CGRectMake(rowWidth*0.1+newView.frame.origin.x, rowHeight*0.2+newView.frame.origin.y, rowWidth*0.8, rowHeight*0.6);
UIButton *largeMoreButton = [UIButton buttonWithType:UIButtonTypeCustom];
largeMoreButton.tag = kLargeMoreBtnTag;
[largeMoreButton setTitle:#"Add Photo" forState:UIControlStateNormal ];
[largeMoreButton setFrame: largeButtonFrame];
// I check the size of the button frame.
DLog(#"large more btn frame: %d, %d, %d, %d", largeMoreButton.frame.origin.x, largeMoreButton.frame.origin.y, largeMoreButton.frame.size.width, largeMoreButton.frame.size.height);
etc.
The problem is that when I get the button back after the setFrame, it is huge. Here is the output from the log. The button thinks it is 1076101120 high!
large more btn frame: 0, 1077706752, 0, 1076101120
I checked the value of the largeButtonFrame rectangle in the debug log, and it is as I would expect.
(gdb) print largeButtonFrame
$1 = {
origin = {
x = 28.5,
y = 10
},
size = {
width = 228,
height = 30
}
}
In the end, when the view is shown in the tableView, I get this error message, and a bunch of CGContext errrors.
-[<CALayer: 0xff7b550> display]: Ignoring bogus layer size (320.000000, 1120403456.000000)
-[<CALayer: 0xff778a0> display]: Ignoring bogus layer size (300.000000, 1120403456.000000)
When my table is shown, the buttons look like the right size, but this cell basically extends forever in the table view, and I can't scroll to any of the other cells behind it.
I've also tried to set the button size different ways (e.g. set the button bounds, and then center it to the view. Or use the UIButton buttonWithType creator, then setting the frame), but none of these seem to make a difference.
Googling the error message, this error message only seems to happen when folks are trying to do animation. But I am not trying to do any animation here, just setting some buttons.
Uh yea... it's a float.
DLog(#"large more btn frame: %f, %f, %f, %f", largeMoreButton.frame.origin.x, largeMoreButton.frame.origin.y, largeMoreButton.frame.size.width, largeMoreButton.frame.size.height);
With the warnings you are getting when you're running the app, I'm not entirely sure what those are, but I'd be willing to bet you aren't using a float value for the size, that's just based on the numbers it's giving you, so I'm not 100% sure.
In my app I move the table view (in order to make the text fields visible when the keyboard appears). The view is looks following:
alt text http://img34.imageshack.us/img34/5845/view2.png
This is the code I use for resizing the view and moving it up:
static const NSUInteger navBarHeight = 44;
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
tableView.frame = CGRectMake(0, navBarHeight, appFrame.size.width, appFrame.size.height-navBarHeight-216); //216 for the keyboard
NSIndexPath *indPath = [self getIndexPathForTextField:textField]; //get the field the view should scroll to
[tableView scrollToRowAtIndexPath:indPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
The problem is that when the view is moved up it also moves 3 pixels into right direction (it is hard to see the difference in the screenshot, but it is visible when the animation is on and I measured the difference with PixelStick tool). Here it is how it looks after the move:
alt text http://img179.imageshack.us/img179/3310/iphonesimulator.png
My analysis shows that scrolling the table does not influence the move to the right.
Any ideas what is wrong in the code above that makes the view move to the right?
perhaps try changing this line :
tableView.frame = CGRectMake(0, navBarHeight, appFrame.size.width, appFrame.size.height-navBarHeight-216); //216 for the keyboard
to
tableView.frame = CGRectMake(tableView.frame.origin.x, navBarHeight, appFrame.size.width, appFrame.size.height-navBarHeight-216); //216 for the keyboard
just in case the origin.x of the tableview isn't at 0?
I have 3 "pages" (page 0, page 1, page 2) in a UIScrollView that are snapped to by finger swipes. There is a UIPageControl there too. The UIScrollView starts off presenting page 0. What I want to do is present page 3 FIRST sometimes. How can I do this programmatically.
Simply setting currentPage (of UIPageControl) to the page number does nothing by the way.
(From the PageControl example)
To go directly to a particular section of the scrollView use
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
I just implemented the same, e.g scrollview and page control and used the
pageControl.currentPage = {pageNumber};
which worked perfectly, are you sure that the pageControl outlet is set correctly in Interface Builder (if you're using it).
If the problem is that the scrollView is not working, and not the pageControl. Then make sure that you have the contentsize of the scrollView set correctly.
scrollView.contentSize = CGSizeMake(320*numberOfPages, scrollView.frame.size.height);
To this scrollview you then add the content to each section
page1ViewController.view.frame = CGRectMake(0, 0, 320, 200);
[scrollView addSubview:page1ViewController.view];
Next page gets pushed over 1 screen width
page2ViewController.view.frame = CGRectMake(320, 0, 320, 200);
[scrollView addSubview:page2ViewController.view];
I am writing an iPhone app with a tab bar and navigation bar. At a certain point, I am pushing an instance of my DetailsViewController class onto the navigation controller stack to show it.
This controller creates its view hierarchy in code: the controller's view property is set to a UIScrollView, which contains a plain UIView (let's call it "contentView") sized to hold all the content to be shown. At the bottom of this contentView, I have four UIButtons.
Now when I run the app (in the simulator at present), and scroll to the bottom of the view, the top two buttons respond to touches; the third responds to touches only in the top portion of it, and the lower button doesn't respond to touches at all. By clicking in various parts of the third button, it appears that the lower 93 pixels of the scroll view is not passing touch events through to its subviews.
93 is suspicious: it's also the combined height of the tab bar (49 pixels) and navigation bar (44 pixels). Yet the navigation bar and tab bar are outside the scroll view. Any suggestions why this might be happening?
Here's the code in question:
- (void)loadView
{
CGRect frame = [[UIScreen mainScreen] applicationFrame];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:frame];
scrollView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
scrollView.delegate = self;
self.view = scrollView;
UIView *contentView = [[UIView alloc] initWithFrame:scrollView.bounds];
contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[scrollView addSubview:contentView];
CGSize viewSize = contentView.bounds.size;
CGSize size;
CGFloat y = 0;
/* Snip creating various labels and image views */
/* Actions view creates and lays out the four buttons; its sizeThatFits:
** method returns the frame size to contain the buttons */
actionsView = [[PropertyDetailActionsView alloc] initWithFrame:CGRectZero];
actionsView.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth);
actionsView.delegate = self;
size = [actionsView sizeThatFits:viewSize];
actionsView.frame = CGRectMake(0, y, size.width, size.height);
[contentView addSubview:actionsView];
y += size.height;
[contentView setFrame:CGRectMake(0, 0, viewSize.width, y)];
scrollView.contentSize = contentView.frame.size;
[contentView release];
[scrollView release];
}
As I suggested on Twitter yesterday, it may have something to do with the flexible bottom margin set to the actionsView.
That suggestion did not resolve the problem, yet it lead to the right direction. By removing the flexible height of the contentView the problem has been fixed.
So if anyone out there is having similar problems, try to play with your autoresizingMasks.
also make sure all your content views are the height that covers the bottom button.
I make each view a different color to see them.