UIScrollView Height Not Working After Showing Modal - ios

I'm retrieving json data from server. The json data includes some images and more text and last but not least json size is not predictable.
Here is how I retrieve json:
-(void)viewWillAppear:(BOOL)animated {
if (self.jsonUrl == nil) {
// This control is about MWPhotoBrowser. If user returned from photo browser do not retrieve data twice
self.view.layer.shadowOpacity = 0.75f;
self.view.layer.shadowRadius = 10.0f;
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underRightViewController isKindOfClass:[DetailContextViewController class]]) {
self.slidingViewController.underRightViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailAbout"];
}
self.jsonUrl = [self.exampleAd getAdJSONLink];
NSLog(#"%#", self.jsonUrl); //
[self backgroundTask]; // retrieving data
} else {
// User returned from MWPhotoBrowser so set the current height again/
// This is not working somehow.
[self.scrollView setContentSize:(CGSizeMake(320, currentHeight + 10))];
}
}
I'm adding all those data to an UIScrollView as a subview. Let's say this is B view. So height of scrollview is uncertain. I'm calculating the height and setting like this:
[self.scrollView setContentSize:(CGSizeMake(320, currentHeight + 10))];
That's working well. Here is my problems: If I go back to A from B and again go A to B, content size is not working. Scrolling not working too, but my currentHeight is showing the right value. Even the retrieving method is not working enough, actually there is something like cache.
There is same problem while using MWPhotoBrowser. When I use present modal controller than return to B view again scroll is not working.
What am I doing wrong, any approach or clue would be great.

Related

UIWebView black color at bottom increases with Animation?

There are some posts, where UIWebView bottom is black and can be resolved by two simple ways.
1. Clear Background of UIWebView
2. Set Opaque to NO.
However, this only solves problem for static UIWebView which is not changing its Frame or Constraints.
In my case, I have a UIWebView, It is very simple Drag and Drop on Storyboard's ViewController's View. No Inheritance. I set Background clear and set opaque to NO.
It looks fine up to now. But when I apply animation, using Facebook POP library
1. SetOpaque = YES, With Animation is clips the UIWebView's content showing black color.
2. SetOpaque = NO, With Animation is clips the UIWebView's content showing nothing (a View or something comes in front)
-(void) setConstraint {
_topConstraintValue = self.topConstraint.constant - 200;
NSLog(#"Value is UP %f " ,_topConstraintValue);
}
- (IBAction)animateUp:(UIButton *)sender {
[self setConstraint];
[VSAnimation popChangeConstraintForBasicAnimation:self.topConstraint begin:0.5 newConstant:_topConstraintValue withDuartion:0.5 isEaseInAnimation:NO withCompletionBlock:nil];
}
-(void) setConstraintDown {
_topConstraintValue = 0;
_topConstraintValue = self.topConstraint.constant;
NSLog(#"Value is Down %f " ,_topConstraintValue);
}
- (IBAction)animateDown:(UIButton *)sender {
[self setConstraintDown];
[VSAnimation popChangeConstraintForBasicAnimation:self.topConstraint begin:0.5 newConstant:[self getAnimatableConstraint:_topConstraintValue] withDuartion:0.5 isEaseInAnimation:NO withCompletionBlock:nil];
}
-(float)getAnimatableConstraint:(float)constant{
return constant+200.0;
}
-(float)getReverseAnimatableConstraint:(float)constant{
return constant-200.0;
}
Where, method inside VS is as below
//VSAnimation.m
+(void)popChangeConstraintForBasicAnimation:(NSLayoutConstraint *) layoutConstraintToPopChange begin:(float) beginTime newConstant:(CGFloat) newConstant withDuartion:(float)duration isEaseInAnimation:(BOOL)isEaseIn withCompletionBlock:(void (^)(POPAnimation *anim, BOOL finished)) completitionBlock{
NSString *key = [NSString stringWithFormat:#"constraints_changed_%#", layoutConstraintToPopChange];
POPBasicAnimation *basicAnim = [layoutConstraintToPopChange pop_animationForKey:key];
if(basicAnim){
basicAnim.toValue = #(newConstant);
basicAnim.completionBlock = completitionBlock;
}else{
basicAnim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayoutConstraintConstant];
if(isEaseIn)
basicAnim.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
else
basicAnim.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
basicAnim.toValue = #(newConstant);
basicAnim.completionBlock = completitionBlock;
basicAnim.beginTime = [self timeWithDelay:beginTime];
basicAnim.delegate = self;
basicAnim.duration = duration;
[layoutConstraintToPopChange pop_addAnimation:basicAnim forKey:key];
}
}
What is this black line/transparent line at bottom.
How to stop this from increasing when one animates UIWebView.
IMAGES:
SHOWING ANIMATION UP & ANIMATION DOWN.
#VS, After reading you source code, I saw the constraint of the 2nd webview seems to be set wrongly. After I removed the height constraint WV2.height = 0.095 * height, the problem disappeared. You have to set the WV2's height constraint properly.

Proper way to display UICollectionView with paging

I've read many many SO solutions about UICollectionView with paging. I myself also work with those solutions:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat pageWidth = self.collectionView.frame.size.width;
self.lbPaging.text = [NSString stringWithFormat:#"%d/%d", self.collectionView.contentOffset.x / pageWidth, totalPage];
}
OR
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = self.collectionView.frame.size.width;
self.lbPaging.text = [NSString stringWithFormat:#"%d/%d", self.collectionView.contentOffset.x / pageWidth, totalPage];
}
Yeah, this work fine most the time. But now I experienced something unexpected:
When user scroll fast enough, it'll get past the method above, which may cause the paging malfunction (like 15/13 at the last page, or showing 3/5 even though it's the first page).
Precisely for us developer or tester, to reproduce this bug, keep your finger touch on the scroll view and start to scroll. When you're nearly out of the edge (where normally, you'll release your finger), touch the other side of the edge and keep scrolling. It's easier to reproduce on real device.
So I'm asking if anyone know a proper way to display the page navigation? Well, without UIPageViewController (I'd like to display the numeric page, not the dots).
EDIT
I don't know if this problem is critical or not, but I think maybe it is, because I'm performing loading data when scrolling to next page. Recently, I've got crash at this (it's really hard to debug, like at which step it got crash):
[self.collectionView performBatchUpdates:^{
NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];
for (NSInteger index = 0; index < next2page.count; index++ ) {
[arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:(index + offset) inSection:0]];
}
[self.collectionView insertItemsAtIndexPaths:arrayWithIndexPaths];
} completion:nil];
Exception is something like this: Fail to insert items to index path in section 0 (has only 69 row, insert to indexPath:73)
hello i have create button in UICollectionView like load more data and function is given below:-
- (void)viewDidLoad {
//declare page inedex initial base 0.
self.pageIndex = 0;
[self loadMoreData];
}
after you call load more data function page index will increase here i want my page index like 0,20,40 so i have create self.pageIndex+= 20 u can change according to your want
-(void)loadMoreData
{
self.isFromMoreData = TRUE;
self.pageIndex+= 20;
NSLog(#"loadMoreData %d and self.index %d",self.pageIndex,self.index);
[self loadDataIntoCollectionView];//this function calls api
}
******************another way is given below*******************************
use UIRefreshControl.
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl = refreshControl;
refreshControl.backgroundColor = [UIColor whiteColor];
refreshControl.tintColor = [UIColor grayColor];
[refreshControl addTarget:self action:#selector(loadMoreData) forControlEvents:UIControlEventValueChanged];
self.myCollectionView.pagingEnabled = YES;
[self.myCollectionView addSubview:refreshControl];
self.myCollectionView.alwaysBounceVertical = YES;
and call the same function loadMoreData that i have declare above.
Hope this help you...
please referred my image

create a UILabel when view appears and destroy it when view disappears

For the tutorial for my app, I am trying to create a UILabel that drifts across the displayed screen when a view appears and then is destroyed so that if the user comes back to that view during the tutorial, the UILabel will be created anew and again drift across the page. Here's a sample of one of the custom view controllers I am displaying with my UIPageViewController:
//this is just a custom UILabel with some padding
#property (nonatomic) PaddedLabel *directionsLabel;
//I have tried setting UILabel to nil or removing it from view
-(void)viewWillDisappear:(BOOL)animated
{
NSLog(#"view is disappearing");
//this does not remove the label
self.directionsLabel = nil;
//nor does this
[self.directionsLabel removeFromSuperview];
}
- (void)viewDidAppear:(BOOL)animated
{
[self messageTutorial];
}
- (void)messageTutorial
{
CGFloat width = [[UIScreen mainScreen] bounds].size.width;
CGFloat height = [[UIScreen mainScreen] bounds].size.height;
PaddedLabel *directionsLabel = [[PaddedLabel alloc] initWithFrame:CGRectMake(_width/2, _height/2, 100, 100)];
directionsLabel.text = #"test";
CGRect f = directionsLabel.frame;
f.size = size;
directionsLabel.frame = f;
directionsLabel.center = self.view.center;
f = directionsLabel.frame;
f = directionsLabel.frame;
f.origin.y = .1*height;
directionsLabel.frame = f;
[self.view addSubview:directionsLabel];
[UIView animateWithDuration:TUTORIAL_DISAPPEAR_TIME animations:^{
directionsLabel.alpha = .5;
CGRect f = directionsLabel.frame;
f.origin.y = height - f.size.height*1.4;
directionsLabel.frame = f;
NSLog(#"animating");
} completion:^(BOOL finished) {
[directionsLabel removeFromSuperview];
//this also doesn't actually remove the label
}];
}
The problem is that if the user pages back to see this view she now sees a new label and the old one, so that if you page back and forth back and forth you end up with many many labels all saying the same thing, in different stages of progressing across the screen.
How can I remove the UILabel when the view disappears and add/create a new one when the view appears/reappears?
Thank you.
The code in your viewWillDisappear method is backwards. You need:
- (void)viewWillDisappear:(BOOL)animated {
NSLog(#"view is disappearing");
[self.directionsLabel removeFromSuperview];
self.directionsLabel = nil;
}
As you had it, setting self.directionsLabel to nil before trying to remove it results in a no-op.
Also, be sure to set self.directionsLabel when you create the label.
Instead of setting your label to nil and effectively destroying the label object (assuming automatic reference counting is on) rather use the following method to hide and show the label as and when your need it.
[self.directionsLabel setHidden:YES]; // hides it
[self.directionsLabel setHidden:NO]; // shows it
You've got the right idea setting objects you're not using to nil and removing them from the super view but it's over kill. A UILabel object uses a negligible amount of memory and you're better off creating the object once and then changing it's properties as you need to.
You don't seem to be setting self.directionsLabel to anything when you create the directionsLabel inside the messageTutorial method. It is a local instance of the label there. You should set it in the method somewhere.
Afterwards, removing it from the superview in viewWillDisappear will work (tested to verify).

Demand loading a UIScrollView

I would like to implement an app using a UIScrollView with paging, similar to the apple weather app.
But I am a little concerned about performance. The example implementation I have been using loads all of the views then the application launches. After a certain point, once this prove slow?
I wonder how Apple's camera roll is dealing with this, where a user may have 100+ photos that can be scrolled through. Should I try to figure out a way to build the view only when it is needed? Or maybe there is a way to replicate the dequeue reusable cell technique from a UITableView, only for horizontal view loading, since each view will have the same layout.
By far the most efficient solution (and this is used in many photo-browsing apps such as Facebook, and probably the native Photos app too) is going to be to load the content on-demand, just as UITableView does. Apple's StreetScroller sample project should get you on the right track.
A very efficient solution, is to make sure to reuse any views whenever possible. If you are going to be simply displaying images, you could use a subclass of UIScrollView, and layout these reusable views within layoutSubviews. Here you could detect what views are visible and not visible and create the subviews as needed.
An example dequeuing function may look like:
- (UIImageView *)dequeueReusableTileWithFrame:(CGRect) frame andImage:(UIImage *) image
{
UIImageView *tile = [reusableTiles anyObject];
if (tile) {
[reusableTiles removeObject:tile];
tile.frame = frame;
}
else {
tile = [[UIImageView alloc] initWithFrame:frame];
}
tile.image = image;
return tile;
}
Where reusableTiles is just an iVar of NSMutableSet type. You could then use this to load fetch any currently offscreen image views and quickly and easily bring them back into view.
Your layoutSubviews may look something like:
- (void)layoutSubviews {
[super layoutSubviews];
CGRect visibleBounds = [self bounds];
CGPoint contentArea = [self contentOffset];
//recycle all tiles that are not visible
for (GSVLineTileView *tile in [self subviews]) {
if (! CGRectIntersectsRect([tile frame], visibleBounds)) {
[reusableTiles addObject:tile];
[tile removeFromSuperview];
}
}
int col = firstVisibleColumn = floorf(CGRectGetMinX(visibleBounds)/tileSize.width);
lastVisibleColumn = floorf(CGRectGetMaxX(visibleBounds)/tileSize.width) ;
int row = firstVisibleRow = floorf(CGRectGetMinY(visibleBounds)/tileSize.height);
lastVisibleRow = floorf(CGRectGetMaxY(visibleBounds)/tileSize.height);
while(row <= lastVisibleRow)
{
col = firstVisibleColumn;
while (col <= lastVisibleColumn)
{
if(row < firstDisplayedRow || row > lastDisplayedRow || col < firstDisplayedColumn || col >lastDisplayedColumn)
{
UImageView* tile = [self dequeueReusableTileWithFrame:CGRectMake(tileSize.width*col, tileSize.height*row, tileSize.width, tileSize.height) andImage:YourImage];
[self addSubview:tile];
}
++col;
}
++row;
}
firstDisplayedColumn = firstVisibleColumn;
lastDisplayedColumn = lastVisibleColumn;
firstDisplayedRow = firstVisibleRow;
lastDisplayedRow = lastVisibleRow;
}
I used something similar to this to tile in areas of a line when I was working with an exceptionally large area of a scroll view and it seemed to work quite well. Sorry for any typos that I may have created when updating this for an image view instead of my custom tileView class.

How to update iOS PhotoScroller sample code

I'm using altered sample code from PhotoScroller within my app. I have a table view of image thumbnails, and I can pass the array of images that populate that table to PhotoViewController. Currently, PhotoViewController starts with the first image in my array and I can scroll back and forth. This works properly as Apple's sample code.
Now What I want to do is tap a table cell with thumbnail, and start scrolling images beginning with the image in my array at that index. Ex: if I have 5 images in a table and I tap image #3, I want the first image in PhotoViewController to be that third image, and able to scroll left or right to #2 or #4. Hope this makes sense.
I see in PhotoViewController that sub views are being added per image. Any way I can tell it "jump to view #3" without destroying the other views or their overall order of appearance? Any ideas or advice is welcome. Code can be found on the iOS developer site for PhotoScroller sample code.
Ok, I'm rambling... Thanks in advance for your help!
The way I do this is to have a variable called startingPage which gets set in the initialiser of the photo view controller. Then when the pages are being created, first set the correct offset for the scroll view.
So in the PhotoScroller case that would be in loadView. Like so:
- (void)loadView
{
// Step 1: make the outer paging scroll view
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView.pagingEnabled = YES;
pagingScrollView.backgroundColor = [UIColor blackColor];
pagingScrollView.showsVerticalScrollIndicator = NO;
pagingScrollView.showsHorizontalScrollIndicator = NO;
pagingScrollView.contentSize = [self contentSizeForPagingScrollView];
pagingScrollView.delegate = self;
self.view = pagingScrollView;
// Set the content offset of the scrollview
CGRect bounds = pagingScrollView.bounds;
CGPoint contentOffset = CGPointMake(bounds.size.width * startingPage, 0.0f);
[pagingScrollView setContentOffset:contentOffset animated:NO];
// Step 2: prepare to tile content
recycledPages = [[NSMutableSet alloc] init];
visiblePages = [[NSMutableSet alloc] init];
[self tilePages];
}

Resources