Change View in UIScrollView with NSTimer - ios

I am using the following code in order to create a UIScrollView:
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scroll.pagingEnabled = YES;
NSInteger numberOfViews = 3;
for (int i = 0; i < numberOfViews; i++) {
CGFloat yOrigin = i * self.view.frame.size.width;
UIView *awesomeView = [[UIView alloc] initWithFrame:CGRectMake(yOrigin, 0, self.view.frame.size.width, self.view.frame.size.height)];
awesomeView.backgroundColor = [UIColor colorWithRed:0.5/i green:0.5 blue:0.5 alpha:1];
[scroll addSubview:awesomeView];
}
scroll.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews, self.view.frame.size.height);
[self.view addSubview:scroll];
The Question is: How do I implement an NSTimer in order to change the page every 4 seconds?
[NSTimer scheduledTimerWithTimeInterval:4.0f
target:self
selector:#selector(updateCounter:)
userInfo:nil
repeats:YES];
I am struggling to write the updateCounter method. Please help
- (void)updateCounter:(NSTimer *)theTimer {
NSInteger numberOfViews = 3;
int i = 0; i++;
if (i < numberOfViews) {
yOrigin = i * self.view.frame.size.width;
[scroll scrollRectToVisible:CGRectMake(yOrigin, 0, self.view.frame.size.width, self.view.frame.size.height) animated:YES];
}
return; }
OK, so with this code, NSTimer changes from view 1 to view 2, but it stops, it does not change after the next 4 seconds to view 3. What I want to do is to change from view 1, to view 2, after 4 seconds, then to view 3, after 4 seconds, and so on. I want to have as many views as I need.

you are doing everything right. Now you need to implement updateCounter so that the scroll of the scrollView happens automatically. maintain global width counter. Keep updating this counter in every call to updateCounter. You could do this like so -
int global_width = self.view.frame.size.width;
int global_height = self.view.frame.size.height;
- (void) updateCounter
{
int width = (global_width%self.view.frame.size.width)*self.view.frame.size.width;
[yourScrollView scrollRectToVisible:CGRectMake(0, 0, width, global_height) animated:YES];
global_width += self.view.frame.size.width;
return;
}
This way you keep cycling between the pages automatically. Hoep this works, all of it is typed freehand. But the concept is correct.

If you want to update a counter every four seconds, call your updateCounter method this way:
[NSTimer scheduledTimerWithTimeInterval:4.0f
target:self
selector:#selector(updateCounter)
userInfo:nil
repeats:YES];
There's two differences in what you did. #1, the time interval is 4 seconds. #2, if you don't have any parameters going into the updateCounter method, don't append a colon to the selector.
And then your updateCounter method:
- (void) updateCounter
{
// what view are you modifying?
// the content view or a subview within the ScrollView's contentView ?
}

Related

How to autoscroll images one by one by the interval of 2 seconds, using Objective C?

I have made scrollview for the few collection of images and I want it to autoscroll the images one by one by the interval of 2 sec. By the below code I could able to make all images slide at a time, but I want one image to scroll then other with respect to time.
-(void)scrollPages{
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0, self.view.frame.size.width, self.view.frame.size.height)];
scrollView.contentSize = CGSizeMake(320, 465);
[scrollView setScrollEnabled:YES];
[scrollView setPagingEnabled:YES];
[scrollView setAlwaysBounceVertical:NO];
[self.uiSubView addSubview:scrollView];
NSMutableArray *arrImage = [NSMutableArray arrayWithObjects:#"a.jpeg", #"cat.jpg", #"s.jpeg",#"ss.jpeg", nil];
for (int i = 0; i < [arrImage count]; i++)
{
CGFloat xOrigin = i * scrollView.frame.size.width;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOrigin, 0, scrollView.frame.size.width, scrollView.frame.size.height)];
[imageView setImage:[UIImage imageNamed:[arrImage objectAtIndex:i]]];
[imageView setContentMode: UIViewContentModeScaleAspectFit];
[scrollView addSubview:imageView];
}
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width * [arrImage count], scrollView.frame.size.height)];
CGFloat currentOffset = scrollView.contentOffset.x;
if(currentOffset < 2500){
CGFloat newOffset = currentOffset + 1250;
[UIScrollView beginAnimations:nil context:NULL];
[UIScrollView setAnimationDuration:3];
[scrollView setContentOffset:CGPointMake(newOffset,0.0) animated:YES];
}
Try simple recursion with dispatch_after function.
Something like this:
-(void)scrollToNextImage{
//place here code for computing and setting scrollview offset
_weak typeof(self) weakSelf = self; //for avoiding retain cycle
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf scrollToNextImage];
});
}
Please be aware that with this case images will be scrolled even when viewcontroller will disappear. Recursion will end only after closing viewcontroller. If you don't want such behavior you can add extra condition for checking if viewcontroller is visible before dispatching next scroll - you can check how to do his here: How to tell if UIViewController's view is visible

UIpagecontrol Need Animation Rigth to Left

Using UIControlpage in my application. load the image and display in page control successfully. but i want to display the images animation like right to left move. Using timer call page control and increase the array count.
//// using NSTimer to call function to show the animation.
[NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(loadNextController)
userInfo:nil
repeats:YES];
ScrollViewPage = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, frameX, frameY)];
ScrollViewPage.pagingEnabled = YES;
ScrollViewPage.backgroundColor=[UIColor redColor];
ScrollViewPage.delegate = self;
ScrollViewPage.backgroundColor = [UIColor clearColor];
ScrollViewPage.contentSize = CGSizeMake(frameX, frameY);
ScrollViewPage.showsHorizontalScrollIndicator = NO;
ScrollViewPage.pagingEnabled = YES;
pageControl = [[UIPageControl alloc] init];
pageControl.frame = CGRectMake(100,self.view.frame.size.height-100,self.view.frame.size.width-200,100);
pageControl.numberOfPages = [_pageImages count];
pageControl.currentPage = 0;
[self.view addSubview: ScrollViewPage];
for(int i = 0; i < [_pageImages count]; i++)
{
NSURL *url = [NSURL URLWithString:[_pageImages objectAtIndex:i]];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage *tmpImage = [UIImage imageWithData:data];
_backgroundImageView = [[UIImageView alloc] initWithImage:tmpImage];
_backgroundImageView.frame = CGRectMake(frameX * i, 0.0, frameX, frameY);
[ScrollViewPage addSubview:_backgroundImageView];
}
ScrollViewPage.contentSize = CGSizeMake(frameX*[_pageImages count], frameY);
pageControl.backgroundColor=[UIColor orangeColor];
[self.view addSubview:pageControl];
[pageControl addTarget:self action:#selector(pageTurn:) forControlEvents:UIControlEventValueChanged];
///// Here call the timer function
- (void)loadNextController
{
pageControl.currentPage = (pageControl.currentPage+1)%self.pageImages.count;
ScrollViewPage.contentOffset = CGPointMake(pageControl.currentPage * self.view.bounds.size.width, 0);
}
Here i need to show left to right move in uipagecontrol. help me..
In general you should always write what is your current result, what is the expected result and what have you tried.
I can only guess the issue you are facing is there are no animations.
The scroll view has a method setContentOffset:animated which you can use to animate the transition. Another approach is to use UIView animateWithDuration and sett the offset in the method block.
Try any or both of these...
[ScrollViewPage setContentOffset:CGPointMake(pageControl.currentPage * self.view.bounds.size.width, 0) animated:YES];
Or
[UIView animateWithDuration:0.2 animations:^{
ScrollViewPage.contentOffset = CGPointMake(pageControl.currentPage * self.view.bounds.size.width, 0);
}];
EDIT: Loop images.
To loop images you really only need 2 images on the scroll view at the time. I will show you the concept with 3 and you can try and play around with it.
NSArray *allImages;
NSInteger currentIndex = 0;
UIScrollView *scrollView;
UIImageView *imageViews[3];
- (void)begin {
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*3.0, scrollView.frame.size.height); // always have 3 images at the time
scrollView.contentOffset = CGPointMake(scrollView.frame.size.width, 0.0); // put to center
for(int i=0; i<3; i++) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(scrollView.frame.size.width*i, 0.0, scrollView.frame.size.width, scrollView.frame.size.height)];
[scrollView addSubview:imageView];
imageView[i] = imageView;
}
[self layoutForIndex:currentIndex];
}
- (void)nextImage {
currentIndex++;
[self layoutForIndex:currentIndex];
scrollView.contentOffset = CGPointZero;
[scrollView setContentOffset:CGPointMake(scrollView.frame.size.width, 0.0) animated:YES]
}
- (void)layoutForIndex:(NSInteger)index {
if(allImages.count > 0) { // we need at least one image to do something
for(int i=0; i<3; i++) {
// do the circling
NSInteger imageIndex = index-1+i;
while(imageIndex < 0) imageIndex+=allImages.count;
while(imageIndex >= allImages.count) imageIndex-=allImages.count;
imageViews[i].image = imageViews[imageIndex];
}
}
}
But in general for what you are doing you do not even need a scroll view. On next you can simply add another image view next to the current one and then use the UIView animation to reposition both of the image views.

ios - Delete or reset memory used when going back to root viewcontroller

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;
}

Issue with UIScrollView within UIScrollView

I have a UIScrollView in my storyboard that scrolls vertically. Inside of this scrollView, I have programmatically created a horizontal UIScrollView.
The vertical scrollView is called scroller. The horizontal UIScrollView is called scrollInfo. For some reason i am unable to register when the horizontal scrollInfo is being used. Any ideas on why this isn't working?
This is in my viewDidLoad:
scrollInfo = [[UIScrollView alloc] initWithFrame:CGRectMake(0,
155,self.view.frame.size.width, self.view.frame.size.height/4)];
//This will create a scrollview of device screen frame
scrollInfo.scrollEnabled = YES;
NSInteger numberOfViews = 3;
for (int i = 0; i < numberOfViews; i++) {
CGFloat xOrigin = i * self.view.frame.size.width;
UIView *awesomeView = [[UIView alloc] initWithFrame:CGRectMake(xOrigin, 0,
self.view.frame.size.width, self.view.frame.size.height/4)];
awesomeView.backgroundColor = [UIColor colorWithRed:0.5/i green:0.5 blue:0.5
alpha:1];
[scrollInfo addSubview:awesomeView];
}
// 3 views added horizontally to the UIScrollView by using xOrigin.
scrollInfo.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews,
self.view.frame.size.height/4);
[scroller addSubview:scrollInfo];
//Add scrollview to viewcontroller
scrollInfo.pagingEnabled = YES;
pageControl = [[UIPageControl alloc] init]; //SET a property of UIPageControl
pageControl.frame = CGRectMake(0,200,self.view.frame.size.width,
self.view.frame.size.height/8);
pageControl.numberOfPages = 3; //as we added 3 diff views
pageControl.currentPage = 0;
[scroller addSubview:pageControl];
Here is my scrollViewDidScroll method:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if ([mainTableView isEqual: scrollView]) {
if (mainTableView.contentOffset.y > 0) {
// yourTableView is not on top.
NSLog(#"not top");
}
else {
// yourTableView is already on top.
NSLog(#"is top");
[UIView animateWithDuration:0.5f delay:0
options:UIViewAnimationOptionCurveLinear animations:^{
scroller.contentOffset = CGPointMake(0, 0);
} completion:NULL];
}
}
else {
CGFloat pageWidth = self.view.frame.size.width;
int page = floor((scrollInfo.contentOffset.x - pageWidth / 2 ) / pageWidth) +
1; //this provide you the page number
pageControl.currentPage = page;// this displays the white dot as current page
NSLog(#"page");
}
}
Looks like you forget to connect UIScrollViewDelegate to your scrollviews. After doing this you better operate with scrollview.tag to recognize which scrollview calling delegate

UIView only shows after being called the second time

I have a view controller that is calling a custom UIView via an IBAction.The custom view contains a UIPickerView that slides up from the bottom of the screen and a toolbar with 'cancel' and 'done' buttons above it. The problem is that the view only appears on the screen after being called for the second time. Using breakpoints I can verify that every single line of code is being called both times. Everything seems to be happening the same way each time. Nothing is NIL, and in fact it's like this for the duration that the app is running, not only the first time it's called. You always have to click the button twice to get the view to appear for as long as the app is running.
Admittedly, the code for the custom picker view is not mine. I copied it from someone else's example. I'm not sure if it's the problem or not. I don't see how it could be, but I'm a bit over my head here. This is how I'm calling the view from my view controller.
- (IBAction)statusPickerButtonPressed:(id)sender {
self.scrollPickerView = [[StatusPickerView alloc]init];
[self.navigationController.view addSubview:self.scrollPickerView];
self.scrollPickerView.delegate = self;
self.scrollPickerView.dataSource = self;
}
and here's the custom UIView
#import "StatusPickerView.h"
#interface StatusPickerView ()
#property NSArray *pickerArray;
#property NSInteger selectedRow;
#end
#implementation StatusPickerView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setToolbar];
[self becomeFirstResponder];
float screenWidth = [UIScreen mainScreen].bounds.size.width;
float pickerWidth = screenWidth * 3 / 4;
float xPoint = screenWidth / 2 - pickerWidth / 2;
[self setFrame: CGRectMake(xPoint, 50.0f, pickerWidth, 180.0f)];
self.showsSelectionIndicator = YES;
[self selectRow:3 inComponent:0 animated:YES];
}
return self;
}
-(void)setToolbar
{
_toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
[_toolbar setBarStyle:UIBarStyleDefault];
UIBarButtonItem * btnCancel = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:#selector(barbtnPressed:)];
UIBarButtonItem * flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil action:nil];
UIBarButtonItem * btnDone = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(barbtnPressed:)];
[btnCancel setTag:1];
[btnCancel setStyle:UIBarButtonItemStyleBordered];
[btnDone setTag:2];
[btnDone setStyle:UIBarButtonItemStyleBordered];
NSArray * btnArray = [[NSArray alloc] initWithObjects:btnCancel, flexible, btnDone, nil];
[_toolbar setItems:btnArray];
self.inputAccessoryView = _toolbar;
self.inputView = self;
}
-(BOOL)canBecomeFirstResponder
{
return true;
}
-(void)barbtnPressed:(id)sender
{
NSInteger tag = [sender tag];
switch (tag) {
case 1:
{
[self removeFromSuperview];
break;
}
case 2:{
[self removeFromSuperview];
self.selectedRow = [self selectedRowInComponent:0];
[[NSNotificationCenter defaultCenter]postNotificationName:#"user_selected_new_section" object:self];
}
default:
break;
}
}
-(int)giveSelectedRow{
return self.selectedRow;
}
I'm fully prepared to feel foolish here, as the solution is probably obvious, just not obvious to myself.
edit:
I tried using [self.view.window addSubview:self.scrollPickerView]; instead of [self.navigationController.view addSubview:self.scrollPickerView];, and the behavior is exactly the same.
This line:
[self.navigationController.view addSubview:self.scrollPickerView];
should read:
[self.view addSubview:self.scrollPickerView];
You’re calling -init instead of -initWithFrame:, so your view is ending up with the default frame of CGRectZero. Considering that you’re then making a frame of your own, that call might as well pass that in to start out with:
self.scrollPickerView = [[ScrollPickerView alloc] initWithFrame:CGRectZero];
Alternatively, you could keep the current self.scrollPickerView = … code and change the -initWithFrame: to an -init, like this:
- (id)init
{
float screenWidth = [UIScreen mainScreen].bounds.size.width;
float pickerWidth = screenWidth * 3 / 4;
float xPoint = screenWidth / 2 - pickerWidth / 2;
self = [super initWithFrame:CGRectMake(xPoint, 50.0f, pickerWidth, 180.0f)];
if (self) {
[self setToolbar];
[self becomeFirstResponder];
self.showsSelectionIndicator = YES;
[self selectRow:3 inComponent:0 animated:YES];
}
return self;
}

Resources