UIScrollview not working even after adding setcontentsize - ios

I add a custom view to my UIViewController dynamically. It adds perfectly now, no exception.But the screen is stuck. My scrollview is not functional. I got this problem earlier and people suggested use setContentSize. I did that and it worked fine. Now I have a new scenario.I have 2 screens.In screen A i save values .Then i click a bar button item on screen A and go to screen B. Here in screen B (it's a tableviewcontroller) I select one row and go back to screen A and fill the values accordingly (basically load the saved values that I saved in the beginning of the app). I fill them correctly and also add the scroll view but it is stuck.It doesn't move neither up/down. I have this code written for adding the subview and setting the scroll-view size and frame size.
ITMCustomView *cView = [[ITMCustomView alloc] initWithFrame:CGRectMake(187, 660, 400, 400)
andOrderedItem:#"New"
andTag:self.tagNumber
withFoldArray:self.foldTypeArray
withRollArray:self.rollTypeArray];
cView.tag =self.tagNumber;
NSLog(#"Assigned tag is %d",cView.tag);
cView.delegate = self;
CGPoint scrollPoint = CGPointMake(0.0, (cView.frame.origin.y/500)*400);
[self.scrollView setContentOffset:scrollPoint animated:YES];
[self.scrollView addSubview:cView];
CGFloat scrollViewHeight = 0.0f;
for (UIView *view in self.scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
CGSize newSize = CGSizeMake(320,scrollViewHeight);
[self.scrollView setContentSize:newSize];
NSLog(#"947 the tag number is %d",self.tagNumber);
I check the value of scrollViewHeight..its 3254.000..I changed it to say 4000 as someone suggested increasing height worked. So what am i doing wrong. This question follows another question of mine Navigating back to UIViewController from TableViewController using NSNotifications
If you need more info please ask.Thanks.

Got mine working after I used did appear instead of will appear.
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.scrollView.contentSize = self.viewMain.bounds.size;
}

Check the scrollingEnabled property on the scroll view. Unsurprisingly, it needs to be set to YES. If this is the case and it still doesn't work, check if the view (and its superviews) has userInteractionEnabled set to YES as well. In the debugger, you can do po [self.view recursiveDescription] to get the view hierarchy back, that may give you some helpful information as well.

Related

iOS 8 AutoLayout changing the position of a view

I'm working on an app that I had originally made for iOS 7 which worked perfectly fine, but now after moving to iOS 8, things aren't working properly anymore. Basically, I have a view with a button. When I tap that button, another UIView with a UITextField "slides" up onto the screen from a position below the visible screen area. The problem comes when I tap the UITextField to type into it, where a keyboard comes up, but the view with the UITextField goes back to its initial position off the screen. This was not happening in iOS 7, so I'm assuming this has something to do with the changes to autolayout for iOS 8. Does anyone know what I can possibly do to fix this? I would rather not turn off autolayout if I don't have to, as a good portion of my app depends on it.
Here is some code to show you what I'm referring to. In my example, "locationField" is the button that gets tapped, and "locationView" is the UIView that slides onto the screen:
- (IBAction) locationFieldTapped:(UIButton *)sender {
[self slideViewUp:_locationView];
}
- (void) slideViewUp:(UIView *)slidingView {
if (viewIsSlidUp) {
return;
}
CGRect frame = slidingView.frame;
int availableHeight = self.view.frame.size.height;
// don't move view up if it's already moved up or in the process of moving up
if (frame.origin.y < availableHeight) {
return;
}
viewIsSlidUp = YES;
// move view just off screen for animation start, in case it's not already there
frame.origin.y = availableHeight;
slidingView.frame = frame;
[UIView animateWithDuration:0.5f animations:^{
CGRect newFrame = frame;
newFrame.origin.y = availableHeight - CGRectGetHeight(frame);
slidingView.frame = newFrame;
}];
}
You need to set the constraints of the view you're animating in iOS 8 and the autolayout system then deals with the rest. You can create an IBOutlet to an NSLayoutConstraint and simply change its constant property. Then you call the layoutIfNeeded method on the edited view's super view in the animation block.

Bounds automatically changes on UIScrollView with content insets

I'm using a UIScrollView as my paging scroll view, pagesScrollView. Inside that, I put individual UIScrollViews which are used exclusively for zooming. Inside each of those, I have one view which is the page item which should be zoomable. All of that is inside a UINavigationController with a translucent navbar.
My pagesScrollView has contentInset.top = 64 and bounds.origin.y = -64 (that seems weird to me, but that's what the system is setting automatically for me), and this works just fine. My screen looks great!
However, after I scroll the pagesScrollView even a tiny bit, as soon as scrollViewWillEndDragging is called, the pagesScrollView begins an animated change from bounds.origin.y = -64 to bounds.origin.y = 0 which causes my page items to be obscured by the navbar.
On the left is what it looks like when it loads, on the right is what it looks like after I drag just a few pixels and then let go, it slides up under the navbar (because the bounds.origin.y goes to 0).
The problem is that I don't have any code that is altering the bounds and I don't have any code in the various scroll delegate methods that do anything. I've added a bunch of scroll delegate methods and just added NSLog()s so I can figure out when/where the change is happening, but it's not happening anywhere in my code.
So, I don't know what code I can show you to help you help me.
EDIT: I built a new project from scratch to remove all other variables.. I put a bare UIViewController into a UINavigationController. I put a UIScrollView into my View the entire size of the view. The following code is the entire project.
It turns out the issue (described below) only appears once PAGING IS ENABLED on the UIScrollView! Wtf? :)
Here is a link to download a basic project with only a few lines of code which demonstrates the problem. Just click in the scrollview and you'll see it shift up as the bounds change. http://inadaydevelopment.com/stackoverflow/WeirdScrollViews.zip
How can I have paging enabled on my scrollview without the bounds freaking out during scrolling and shifting everything under the nav bar?
It's possible to set the navbar to opaque and the problem is avoided, but the ideal is to have standard iOS7 behavior so that after the content view is zoomed, THEN the content is allowed to be under the navbar and should show through the translucency normally.
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSArray *colors = #[
[UIColor blueColor],
[UIColor orangeColor],
[UIColor magentaColor],
];
NSArray *zoomerColors = #[
[UIColor greenColor],
[UIColor yellowColor],
[UIColor purpleColor],
];
self.scroller.pagingEnabled = YES;
[self.scroller setContentSize:CGSizeMake(self.scroller.frame.size.width*colors.count, self.scroller.frame.size.height)];
CGRect subviewFrame = CGRectMake(0, 0, 160, 240);
for (int index=0; index < colors.count; index++) {
UIColor *color = [colors objectAtIndex:index];
UIColor *zoomerColor = [zoomerColors objectAtIndex:index];
UIView *subview = [[UIView alloc] initWithFrame:subviewFrame];
subview.backgroundColor = color;
CGRect zoomerFrame = CGRectMake(index*self.scroller.frame.size.width, 0, self.scroller.frame.size.width, self.scroller.frame.size.height);
UIScrollView *zoomer = [[UIScrollView alloc] initWithFrame:zoomerFrame];
[zoomer addSubview:subview];
zoomer.backgroundColor = zoomerColor;
[self.scroller addSubview:zoomer];
}
}
Just switch off Adjust Scroll View Insets
It's an iOS bug. I created the following subclass of UIScrollView to get a log of what happens to y over time and who was pushing it:
#implementation CSScrollView
- (void)setContentOffset:(CGPoint)contentOffset
{
NSLog(#"%0.0f %#", contentOffset.y, [NSThread callStackSymbols]);
NSLog(#"[%#]", self.layer.animationKeys);
[super setContentOffset:contentOffset];
}
#end
(and changed the view class in the storyboard)
When you release your finger, a method called UIScrollView _smoothScrollDisplayLink: starts animating the scroll view to its final position. As per the second log, there's no CAAnimation involved, the scroll view uses its own display link to do its own transition. That custom code appears to make the mistake of animating from y = whatever to y = 0, failing to take the content offset into account.
As a proof-of-concept hack I changed the code to:
#implementation CSScrollView
- (void)setContentOffset:(CGPoint)contentOffset
{
contentOffset.y = -64.0f;
[super setContentOffset:contentOffset];
}
#end
And, unsurprisingly, the problem went away.
You probably don't want to hard code the -64.0f but I'd conclude:
it's an iOS bug;
work around it by rejecting nonsensical values via a subclass of UIScrollView with a suitable custom implementation of - setContentOffset:.
A sensible generic means might be to check the state of self.panGestureRecognizer — that'll allow you to differentiate between scrolls the user is responsible for and other scrolls without relying on any undocumented API or complicated capturing of delegate events. Then if necessary crib the correct contentOffset.y from the current value rather than hardcoding it.
My pagesScrollView has contentInset.top = 64 and bounds.origin.y = -64 (that seems weird to me, but that's what the system is setting automatically for me), and this works just fine. My screen looks great!
It because of iOS 7 sets contentInset.top to 64 on all scrollviews.
Just add this line of code into your view controller and all will work as expected:
-(UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;
}
I checked on your example project.
I have checked you example use below code in viewController.m file
-(void)viewDidLoad
{
if ([[UIDevice currentDevice] systemVersion].floatValue>=7.0) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
}
It's working fine...
It turns out the issue (described below) only appears once PAGING IS ENABLED on the UIScrollView! Wtf? :)
As you said that, If you enable the scroll paging, the UIScrollView will stop at a paging edge after a dragging or any movement, which is promised by the framework. Bounds.origin.y set by zero means that the first page edge matched the scroll view frame edge, cuz you have 64 contentInsets there. So that's not bug, that is what it is. And since your bar is translucent, remember where is your scroll view's frame edge, it's under the bar. In a word, this is not a bug, I think, but a effect of scroll paging.

How to automatically resize mkmapview to fill entire screen on orientation change?

- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
self.mapView.frame = self.view.bounds;
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
CLLocationCoordinate2D startCoord = CLLocationCoordinate2DMake(36.7472, -95.9594);
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:MKCoordinateRegionMakeWithDistance(startCoord, 10000*1609.344, 10000*1609.344)];
[self.mapView setRegion:adjustedRegion animated:YES];
}
That's the code I have right now. When I change the orientation of my iPad from landscape to portrait, the map view's size doesn't change. I would like it to fill the entire view. I have tried searching google and stackoverflow for a solution, but I haven't had any luck.
Any help would be immensely appreciated.
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
self.mapView.frame = self.view.bounds;
}
This will ensure that the map frame will adjust to the view bounds whenever the view controller layout is triggered (like, on autorotation).
You can actually take the set frame line out of viewWillAppear, since viewWillLayoutSubviews runs at initial setup time.
If you are using Autolayout, you can:
- go to the Storyboard, then click on your mapView.
- look for a segmented control on the bottom of Storyboard and click the segment "Pin" .There, add the constrains for left, right, up and down. This should do what you want.
Very simple and no code required.

UIScrollView does not restore properly

I have a Scrollview, it's properties are set in viewDidAppear.
Now when I get to the Scrollview first time there isn't any problem. However I have buttons that are assigned to UINavigationController. So when I press into one of them UINavigationController opens up, when I close the navigation controller, ScrollView does not restore properly. It basically aligns the centre of the screen as previously pressed button location. So if I try to scroll up it does not.
I have tried using this in my viewDidAppear:
scrollView.center = CGPointMake(scrollView.contentOffset.x, scrollView.contentOffset.y);
Which did not quite work. How can I solve this? I am using iOS6.1
Actually I found the answer here:
UIScrollview Autolayout Issue
The exact code that I used is:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
//save the current offset
previousPoint = scrollView.contentOffset;
//set current view to the beginning point
self.scrollView.contentOffset = CGPointZero;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
//retrieve the previous offset
self.scrollView.contentOffset = previousPoint;
}
previousPoint is nothing but a CGPoint variable declared on the implementation.
I've had this problem before too. This answer shows how to overcome this issue.
Basically, you need to set the scrollview's contentOffset appropriately in viewWillAppear: and viewDidDisappear:.
EDIT: Here's another related question that you might find useful, UIScrollview Autolayout Issue.

How to animate scroll a view like "pull to refresh"?

My app is showing the following:
'Sample 1' is just a view to display content. After I click up button, 'Sample 1' will scroll up and a new view 'Sample 2' will be showed from bottom, the final result is :
I think I should append the sample 2 view at the end of up button, and just adjust the frame of sample 1 and up button to show sample 2.
But I don't know the details how to implement it. Is there a easy way to implement this?
Just place your button and the 2 sample view's in the UIScrollview and set the contentsize of the scrollview to the total height of the button and the 2 sample view's.
Next, you could disable the scrolling on the UIScrollView and connect the button to a method scrolling the UIScrollView up.
Assuming you got your UIScrollView and the 'sample' view's as properties in your custom UIViewController class you could do something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
//disable scrolling
self.scrollView.scrollEnabled = NO;
}
//connect this action to you button
- (IBAction)buttonPressed:(id)sender{
//if current position is top scroll down, otherwise scroll up.
if(self.scrollView.contentOffset.y < 1){
[self.scrollView setContentOffset:CGPointMake(0, self.sample1.frame.size.height) animated:YES];
}else{
[self.scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}
}
You can try the enormego (EGO). Refer to this question:
Pull to Refresh (ios)
you can implement this using scroll view. Add the views in a scroll view and when the up button is pressed just scroll to the respective position.
I've done this before and before I get say anything about it, you want to be careful because you're creating a view larger than the screen size and therefor you are technically rendering a larger than regular view all the time. Avoiding this (while not necessary) may let you unload a view from screen if you can.
That aside, have your main view appear in a UIScrollView so you can adjust the view's position.
The code may look like:
- (IBAction)upButtonPress:(id)sender
{
[UIView animateWithDuration:2.0 animations:^{
// Approximate frame origin difference
self.scrollView.contentOffset.y = self.view.frame.size.height - upButton.frame.size.height;
} completion:^(BOOL finished) {
// if necessary, do something when animation completes
}];
}

Resources