I am trying to hide content on only one section (one photo) of my UIScrollView and am using a contentOffsetto access that section like below. If the content offset is between 0 and 320 (the size of my image) I am hiding various elements on the screen. However when the user swipes over to the next photo (i.e. content offset greater than 320) I would like to show the content again. The first portion of my code works great, however I am not sure that there is any detection of the content offset being greater than 320 when the user swipes. I am fairly new with ScrollViews and am not sure if they update the content offset constantly or whether they detect user swipe that would cause an update. Are there any ideas on how I can get the elements hidden to equal NO after the user has scrolled beyond my first image?
if (scroller.contentOffset.x >=0<=320)
{
preview.hidden = YES;
share.hidden = YES;
barView.hidden = YES;
saveButton.hidden = YES;
shaddows.hidden = YES;
}
else if (scroller.contentOffset.x >320)
{
//This part does not work
preview.hidden = NO;
share.hidden = NO;
barView.hidden = YES;
saveButton.hidden = YES;
shaddows.hidden = YES;
}
Here is the rest of my scroller code:
int PageCount = 2;
NSMutableArray *myArray =[[NSMutableArray alloc]initWithObjects:#"12-4.png",#"13-4.png",nil];
scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
scroller.scrollEnabled=YES;
scroller.backgroundColor = [UIColor clearColor];
scroller.pagingEnabled = YES;
[self.view addSubview:scroller];
width=scroller.frame.size.width;
xPos=0;
for (int i=0; i<PageCount; i++)
{
ImgView = [[UIImageView alloc]initWithFrame:CGRectMake(xPos, 0, scroller.frame.size.width, scroller.frame.size.height)];
[ImgView setImage:[UIImage imageNamed:[myArray objectAtIndex:i]]];
[scroller addSubview:ImgView];
scroller.contentSize = CGSizeMake(width, 0);
width +=scroller.frame.size.width;
xPos +=scroller.frame.size.width;
}
Thank you!
Change this line
if (scroller.contentOffset.x >=0<=320)
To
if (scroller.contentOffset.x <= 320)
Because the original doesn't do what you think it will.
This code should be in the scrollViewDidScroll: delegate method (make sure your controller is the scroll view delegate).
Add some log statements so it prints out as the user is scrolling what the content offset it and what page your code thinks it is.
Related
I am trying to build a screen which has 2 UIScrollViews, 1 Main Scroll View which is used as a container and to scroll vertically (this is working fine).
Inside the Main Scroll View, is a second scroll view, which is used for display different images. This needs to be scrolled horizontally so it will page to other images which will also update content details displayed in the Main Scroll View.
When attempting to get these two features to work together, the paging functionality does not work, however if it is outside the main scroll view it will work but will not scroll with the rest of the content.
The Image Scroll View is being detected in the events as well, but doesn't show any ability to scroll.
Below are my 3 functions which are performing the work.
- (void)viewDidLoad
{
[super viewDidLoad];
// Set up the Image Scroll View
ImageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0, screenWidth, homeImage)];
ImageScrollView.scrollEnabled = YES;
ImageScrollView.userInteractionEnabled=YES;
[ImageScrollView setPagingEnabled:YES];
[ImageScrollView setAlwaysBounceVertical:NO];
ImageScrollView.delegate = self;
// Set up the image array
NSArray *imagesArray = [NSArray arrayWithObjects:#"staff1big.png", #"staff2big.png", #"staff3big.png", nil];
// Create each image subview
for (int i = 0; i < [imagesArray count]; i++)
{
CGFloat xOrigin = i * ImageScrollView.frame.size.width;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOrigin, 0, ImageScrollView.frame.size.width, ImageScrollView.frame.size.height)];
[imageView setImage:[UIImage imageNamed:[imagesArray objectAtIndex:i]]];
[ImageScrollView addSubview:imageView];
}
// Set the Content Size and Offset
[ImageScrollView setContentSize:CGSizeMake(ImageScrollView.frame.size.width * [imagesArray count], ImageScrollView.frame.size.height)];
[ImageScrollView setContentOffset:CGPointMake(screenWidth*currentIndex, 0)];
// Get the staff object
dataSource = [DataSource dataSource];
NSArray *staffArray = [dataSource getStaff];
// Setup the Pager Control
self.pageControl = [[UIPageControl alloc] init];
NSInteger placement = (screenWidth/2)-50;
self.pageControl.frame = CGRectMake(placement, homeImage-30, 100, 20);
self.pageControl.numberOfPages = [staffArray count];
self.pageControl.currentPage = currentIndex;
[self setStaff:staffArray[currentIndex]];
// Add the Main Scroll View
MainScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
MainScrollView.delegate = self;
MainScrollView.scrollEnabled = YES;
MainScrollView.userInteractionEnabled=YES;
// Add each object to the correct scroll view
[ImageScrollView addSubview:self.pageControl];
[MainScrollView addSubview:ImageScrollView];
[MainScrollView addSubview:lineView];
[self setDisplayContent]; // note the MainScrollView is added to the self.view in this method along with setting the content size to screenWidth and height is determine by the generated content.
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat pageWidth = ImageScrollView.frame.size.width;
float fractionalPage = ImageScrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
currentIndex = page;
self.pageControl.currentPage = page;
[self displayContent];
}
- (void)displayContent
{
int i = currentIndex;
if (i < 0)
{
i = 0;
} else if (i > 2) {
i = 2;
}
[self setStaff:allStaff[i]];
// remove all from view
for(UIView *subview in [MainScrollView subviews]) {
[subview removeFromSuperview];
}
NSArray *imagesArray = [NSArray arrayWithObjects:#"staff1big.png", #"staff2big.png", #"staff3big.png", nil];
for (int i = 0; i < [imagesArray count]; i++)
{
CGFloat xOrigin = i * ImageScrollView.frame.size.width;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOrigin, 0, ImageScrollView.frame.size.width, ImageScrollView.frame.size.height)];
[imageView setImage:[UIImage imageNamed:[imagesArray objectAtIndex:i]]];
[ImageScrollView addSubview:imageView];
}
[ImageScrollView setContentSize:CGSizeMake(ImageScrollView.frame.size.width * [imagesArray count], ImageScrollView.frame.size.height)];
[ImageScrollView setContentOffset:CGPointMake(screenWidth*currentIndex, 0)];
// Get the staff
dataSource = [DataSource dataSource];
NSArray *staffArray = [dataSource getStaff];
self.pageControl = [[UIPageControl alloc] init];
NSInteger placement = (screenWidth/2) - 50;
self.pageControl.frame = CGRectMake(placement, homeImage-30, 100, 20);
self.pageControl.numberOfPages = [staffArray count];
self.pageControl.currentPage = currentIndex;
[self setStaff:staffArray[currentIndex]];
[ImageScrollView addSubview:self.pageControl];
[MainScrollView addSubview:ImageScrollView];
[MainScrollView addSubview:lineView];
[self setDisplayContent];
}
I do need to refactor some of the code to make more efficient, but at this stage I am just trying to get the horizontal paging to scroll horizontally.
If anyone would possibly be able to help point me in the right direction as to how to fix this issue, it would be greatly appreciated.
Here is a visual of the UI that I am trying to keep but have the image scroll horizontal.
Staff Display
Good day! Is there any way on how to reduce or revert the memory used to a freshly opened app state? I'm developing a Menu app for a restaurant. On the main screen i have a buttons for Main Course,Appetizers,Soups etc. If you click on one category it will take you to another view, That is UINavigation Controller with UITableViewController, now when you click on any row of that UITableView it will take you to another ViewController which contains UIScrollView with images. This Last ViewController has this code to loop many images.
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0,
self.view.frame.size.width,
self.view.frame.size.height)];
self.scrollView.pagingEnabled = YES;
[self.scrollView setAlwaysBounceHorizontal:NO];
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.scrollEnabled = YES;
//setup internal views
NSInteger numberOfViews = 5;
for (int i = 0; i < numberOfViews; i++) {
CGFloat xOrigin = i * self.view.frame.size.width;
image = [[UIImageView alloc] initWithFrame:
CGRectMake(xOrigin, 0,
self.view.frame.size.width,
self.view.frame.size.height)];
image.image = [UIImage imageNamed:[NSString stringWithFormat:
#"main_%d", i+1]];
image.contentMode = UIViewContentModeScaleAspectFit;
[self.scrollView addSubview:image];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updatePrices:) userInfo:nil repeats:YES];
}
//set the scroll view content size
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width *
numberOfViews,
self.view.frame.size.height);
//add the scrollview to this view
[self.view addSubview:self.scrollView];
So basically in 1 Category Lets say Main Course, i have this
http://oi60.tinypic.com/f1fr0j.jpg
Each category i have that setup of views. Now, The main problem is, when i open the app, it only consumes 6MB, then when i Tap a button, to show the Menu for the selected category, it goes up to 17mb, Now When i click anything on the Food lists, and shows the image viewcontroller, it goes up to 68mb. I tried to add a button on each to and add some actions like this
- (IBAction)backToHome:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
self.view = nil;
}
The main problem is, When i go back to the MainViewController, The consumed Memory is there, so the app gets really slow if they select more categories because it increases the memory usage. How can i Reduce or "Clear Cache" of the used memory to prevent slowing the app? Thank you!
Calling imageNamed will always cache the image in the memory to increase speed, so event if you release holder view(s) the memory usage won't drop. Use some other method to load your images(imageWithContentsOfFile or other) and make caching by yourself if you need it at all.
#property(nonatomic, strong) NSMutableDictionary* cachedImages;
-(UIImage*)imageNamedBOOM:(NSString*)aImageName
{
UIImage* result = _cachedImages[aImageName];
if( !result )
{
result = [UIImage imageWithContentsOfFile:aImageName];
_cachedImages[aImageName] = result;
}
return result;
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
[_cachedImages removeAllObjects];
}
And then in your code just call it like this(note that you have to provide image extension png, jpg, etc):
-(void) setupScrollView {
//add the scrollview to the view
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0,
self.view.frame.size.width,
self.view.frame.size.height)];
self.scrollView.pagingEnabled = YES;
[self.scrollView setAlwaysBounceVertical:NO];
//setup internal views
NSInteger numberOfViews = 3;
for (int i = 0; i < numberOfViews; i++) {
CGFloat xOrigin = i * self.view.frame.size.width;
UIImageView *image = [[UIImageView alloc] initWithFrame:
CGRectMake(xOrigin, 0,
self.view.frame.size.width,
self.view.frame.size.height)];
image.image = [self imageNamedBOOM:[NSString stringWithFormat:
#"image_%d.png", i+1]];//make sure here you provide proper image extension JPG, PNG or other
image.contentMode = UIViewContentModeScaleAspectFit;
[self.scrollView addSubview:image];
}
//set the scroll view content size
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width *
numberOfViews,
self.view.frame.size.height);
//add the scrollview to this view
[self.view addSubview:self.scrollView];
}
And in back to home:
- (IBAction)backToHome:(id)sender {
[_cachedImages removeAllObjects]
[self dismissViewControllerAnimated:YES completion:nil];
self.view = nil;
}
I have been following a tutorial for paging through images within a UIScrollview.
The paging with UIScrollview section.
I now want to change this so instead of an UIimageview, it displays a UITextview. With different text as it is paged.
Not sure as to how to implement the textview instead of the imageview.
any ideas?
Thanks
code being used:
- (void)loadPage:(NSInteger)page {
if (page < 0 || page >= self.pageImages.count) {
// If it's outside the range of what you have to display, then do nothing
return;
}
// 1
UIView *pageView = [self.pageViews objectAtIndex:page];
if ((NSNull*)pageView == [NSNull null]) {
// 2
CGRect frame = self.scrollView.bounds;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0.0f;
//UITextView *theTextView;
theTextView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
theTextView.scrollEnabled = NO;
theTextView.editable = NO;
theTextView.text = [NSString stringWithFormat:#"This is a very long text"];
// 3
//UIImageView *newPageView = [[UIImageView alloc] initWithImage:[self.pageImages objectAtIndex:page]];
theTextView.contentMode = UIViewContentModeScaleAspectFit;
theTextView.frame = frame;
[self.scrollView addSubview:theTextView];
// 4
[self.pageViews replaceObjectAtIndex:page withObject:theTextView];
}
}
They are both UIView subclasses. It should work the exact same way. Simply deactivate allowUserInteraction on the UITextViews if you don't want them to scroll and the UIScrollView should scroll the exact same way as if it was filled with UIImageViews.
You'd add the UITextView the exact same way you'd add a UIImageView. Initialize a UITextView, set up any properties you want on it, and add it to the UIScrollView as a subview. So where ever you're adding UIImageViews, replace that code with something like this:
self.theTextView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
self.theTextView.scrollEnabled = NO;
self.theTextView.editable = NO;
... //however else you want to modify your UITextView
[self.theScrollView addSubview:self.theTextView];
I am having problems with UIPageControl and UIScrollView.
- (void)viewDidLoad
{
[super viewDidLoad];
imageArray = [[NSArray alloc] initWithObjects:#"image1.jpg", #"image2.jpg", #"image3.jpg", nil];
for (int i = 0; i < [imageArray count]; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
[self.scrollView addSubview:imageView];
}
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [imageArray count], scrollView.frame.size.height);
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
pageControl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
}
#pragma mark - UIScrollView Delegate
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
}
The problem occurs when I change the orientation to landscape. image1.jpg shares the view with image2.jpg, which is not what I want.
But if I change the orientation back to portrait, the view is doing fine.
The problem is that the page size has changed (i.e. the width of the scrollview) but the width of the images hasn't changed.
One solution would be that when you rotate you re-do the computation that sizes the UIImageViews and computes the scrollview's contentSize. That is, move the for loop and assignment to scrollView.contentSize out of viewDidLoad and into a private method, say sizeImagesAndSetContentSize. Call that from willAnimateRotationToInterfaceOrientation:duration:
Something like the following:
- (void)viewDidLoad
{
[super viewDidLoad];
imageArray = [[NSArray alloc] initWithObjects:#"image1.jpg", #"image2.jpg", #"image3.jpg", nil];
[self sizeImagesAndSetContentSize];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
pageControl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
}
- (void) sizeImagesAndSetContentSize {
for (int i = 0; i < [imageArray count]; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
[self.scrollView addSubview:imageView];
}
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [imageArray count], scrollView.frame.size.height);
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
[self sizeImagesAndSetContentSize];
}
By the way, viewDidLoad is not the place to do geometry calculations -- like things that involve the frame of the scrollView because the geometry isn't set then. in viewDidLoad the sizes of things are the sizes that they were in the storyboard (or nib) and haven't been adjusted to the actual device and the actual orientation. If it works for you so far, it is because you start out in the orientation that the storyboard is laid out. Probably the best place to do that, and thus to call sizeImagesAndSetContentSize is in the method viewDidLayoutSubviews. In fact, if you move the call there, you won't need to explicitly call it on rotation because when rotation occurs the view lays out the subviews and viewDidLayoutSubviews will get called automatically. So I'd suggest:
- (void)viewDidLoad
{
[super viewDidLoad];
imageArray = [[NSArray alloc] initWithObjects:#"image1.jpg", #"image2.jpg", #"image3.jpg", nil];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
pageControl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
}
- (void) sizeImagesAndSetContentSize {
for (int i = 0; i < [imageArray count]; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
[self.scrollView addSubview:imageView];
}
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [imageArray count], scrollView.frame.size.height);
}
- (void)viewDidLayoutSubviews {
[self sizeImagesAndSetContentSize];
}
Addendum:
ADDING TEXT TO THE IMAGE:
To add text on top of the image -- you could add a text element, like a label, "on top" of the scroll view. Consider the screenshot from an app below. In the top-level Cloud Slide Show View there is a full-sceen Scroll View and at the same hierarchy level but further down the list of subviews (and thus "on top" of the scrollview) are a label for a description, 3 buttons, and a UIPageControl. The label is set to resize on rotation via struts and springs (this runs on iOS 5) so you don't have to mess with it.
This application changes the description label to match the image that is currently displayed in the scrollview page -- so it has to detect page changes. This app does that in the scroll view delegate protocol method scrollViewDidEndDecelerating: where it decides which image is on-screen when scrolling stops and fills-in the correct description.
An alternative would be to put put a label on top of each UIImage, but that is messy which is why my app doesn't do that. You'd probably want a view to contain both the UIImage and a label so that repositioning the label would make sense. Probably create that in code... For me, too much trouble.
As an aside, I should say that using page mode in a scroll view is probably not the "best practice" way to do this anymore. I'm converting my app to use a UIPageViewController which should simplify the app. For instance, you don't have to do the resize-on-rotate thing since the individual child VCs of the UIPageViewControl can resize themselves automatically.
i have a modal view that is called from a table view. Whenever i call the modal view, i set a small view, inside the modal view, with some scrollable pictures inside it. The problem is that when i go back to the table view and select another row of the table, the old images are supposed to disappear and the new ones appear instead, but that is not happening. Seems like when i first load the modal view, it fills with the initial 2 pics and when i load it again it keeps adding the new pictures with the old ones..
Here is the code:
- (void)layoutScrollImages {
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
//NSMutableArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake(([self.nomeFotos count] * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
and:
- (void)setScrollingImages {
//self.view.backgroundColor = [UIColor viewFlipsideBackgroundCol];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= [self.nomeFotos count]; i++)
{
NSString *imageName = [NSString stringWithFormat:[self.nomeFotos objectAtIndex:(i-1)]];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
NSLog(#"%#", imageName);
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
i just figured what i wanted, a solution is to remove all the current subviews and then add the new views.. the code is as follow:
for (UIView* subView in [self.view.subviews]) {
[subView removeFromSuperview];
}
I put this code in my view will appear and everytime the view appears, it clears its subviews and the i call the method to add the new subviews (pictures).
Thanks