Reusing 3 views on UIScrollView's Paging - ios

I did the following code where three views can be reused during Pagination in UIScrollView in order to save live memory-->
#pragma mark - UIScrollView Delegates
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat pageWidth = self.view.frame.size.width;
CGPoint aContentOffSet = [[self scrollView] contentOffset] ;
float currPos = aContentOffSet.x;
int selectedPage = roundf(currPos/pageWidth);
[[self pageControl] setCurrentPage:selectedPage];
[self update:selectedPage];
}
#pragma mark - Custom methods
-(void)update:(int) selectedPage{
BOOL view1FrameShallBeUnchanged = false;
BOOL view2FrameShallBeUnchanged = false;
BOOL view3FrameShallBeUnchanged = false;
BOOL aFrame1Matched = false;
BOOL aFrame2Matched = false;
BOOL aFrame3Matched = false;
CGRect aFrame1 = CGRectMake(selectedPage*self.view.frame.size.width, 0.0f, self.view.frame.size.width, self.scrollView.frame.size.height);
CGRect aFrame2 = CGRectMake((selectedPage-1)*self.view.frame.size.width, 0.0f, self.view.frame.size.width, self.scrollView.frame.size.height);
CGRect aFrame3 = CGRectMake((selectedPage+1)*self.view.frame.size.width, 0.0f, self.view.frame.size.width, self.scrollView.frame.size.height);
ViewOnScrollView *aView1 = (ViewOnScrollView*)[[self scrollView] viewWithTag:1234];
ViewOnScrollView *aView2 = (ViewOnScrollView*)[[self scrollView] viewWithTag:12345];
ViewOnScrollView *aView3 = (ViewOnScrollView*)[[self scrollView] viewWithTag:123456];
if(aView1 && aView2 && aView3){
//Check for Frame 1
if(aFrame1.origin.x == aView1.frame.origin.x){
view1FrameShallBeUnchanged = true;
aFrame1Matched = true;
}
else if(aFrame1.origin.x == aView2.frame.origin.x){
view2FrameShallBeUnchanged = true;
aFrame1Matched = true;
}
else if(aFrame1.origin.x ==aView3.frame.origin.x){
view3FrameShallBeUnchanged = true;
aFrame1Matched = true;
}
//Check for Frame 2
if(aFrame2.origin.x == aView1.frame.origin.x){
view1FrameShallBeUnchanged = true;
aFrame2Matched = true;
}
else if(aFrame2.origin.x == aView2.frame.origin.x){
view2FrameShallBeUnchanged = true;
aFrame2Matched = true;
}
else if(aFrame2.origin.x == aView3.frame.origin.x){
view3FrameShallBeUnchanged = true;
aFrame2Matched = true;
}
//Check for Frame 3
if(aFrame3.origin.x == aView1.frame.origin.x){
view1FrameShallBeUnchanged = true;
aFrame3Matched = true;
}
else if(aFrame3.origin.x == aView2.frame.origin.x){
view2FrameShallBeUnchanged = true;
aFrame3Matched = true;
}
else if(aFrame3.origin.x == aView3.frame.origin.x){
view3FrameShallBeUnchanged = true;
aFrame3Matched = true;
}
if(!view1FrameShallBeUnchanged){
if(!aFrame1Matched){
[aView1 setFrame:aFrame1];
}
else if(!aFrame2Matched){
[aView1 setFrame:aFrame2];
}
else{
[aView1 setFrame:aFrame3];
}
[self hideOrShowTheTabs:aView1];
[self hideShowView:aView1];
}
if(!view2FrameShallBeUnchanged){
if(!aFrame1Matched){
[aView2 setFrame:aFrame1];
}
else if(!aFrame2Matched){
[aView2 setFrame:aFrame2];
}
else{
[aView2 setFrame:aFrame3];
}
[self hideShowView:aView2];
}
if(!view3FrameShallBeUnchanged){
if(!aFrame1Matched){
[aView3 setFrame:aFrame1];
}
else if(!aFrame2Matched){
[aView3 setFrame:aFrame2];
}
else{
[aView3 setFrame:aFrame3];
}
[self hideShowView:aView3];
}
}
}
-(void)hideShowView:(ViewOnScrollView*)theView{
if(theView.frame.origin.x<0 || theView.frame.origin.x>[self.scrollView contentSize].width )
theView.hidden = YES;
else{
theView.hidden = NO;
}
}
Comments/Suggestions/Better ways to do the same are welcome..

check out this class ..maybe it can help.. easy to use...just like UITableview
VSScroller

Its ok, but you have too much code (~40 lines) and too much unnecessary processing. You only need to know when one frame matches (let's say the center frame), and also you should do this only when the page is about to change, not on every scroll event.
This way, whenever the left or right page becomes the current page, you move the opposite page to the other side.
Another bug you had is that you should hide the last+1 page when its frame.origin.x is equal (== , or >=) to the content size, not only bigger (>).
#pragma mark - UIScrollView Delegates
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
int selectedPage = roundf(newsPagesView.contentOffset.x/_pageWidth);
if (selectedPage != _currentPage) {
_currentPage = selectedPage;
[self update:selectedPage];
}
}
#pragma mark - Custom methods
-(void)update:(int) selectedPage{
BOOL page1FrameMatched = false;
BOOL page2FrameMatched = false;
BOOL page3FrameMatched = false;
BOOL frameCurrentMatched = false;
CGRect frameCurrent = CGRectMake(selectedPage*_pageWidth, 0.0f, _pageWidth, _pageHeight);
CGRect frameLeft = CGRectMake((selectedPage-1)*_pageWidth, 0.0f, _pageWidth, _pageHeight);
CGRect frameRight = CGRectMake((selectedPage+1)*_pageWidth, 0.0f, _pageWidth, _pageHeight);
NewsPage *page1 = (NewsPage*)[newsPagesView viewWithTag:100];
NewsPage *page2 = (NewsPage*)[newsPagesView viewWithTag:101];
NewsPage *page3 = (NewsPage*)[newsPagesView viewWithTag:102];
if(page1 && page2 && page3){
//Check for Current
if(frameCurrent.origin.x == page1.frame.origin.x){
page1FrameMatched = true;
frameCurrentMatched = true;
}
else if(frameCurrent.origin.x == page2.frame.origin.x){
page2FrameMatched = true;
frameCurrentMatched = true;
}
else if(frameCurrent.origin.x ==page3.frame.origin.x){
page3FrameMatched = true;
frameCurrentMatched = true;
}
if(frameCurrentMatched){
if(page1FrameMatched){
[page1 setFrame:frameCurrent];
[page2 setFrame:frameLeft];
[page3 setFrame:frameRight];
}
else if(page2FrameMatched){
[page1 setFrame:frameRight];
[page2 setFrame:frameCurrent];
[page3 setFrame:frameLeft];
}
else{
[page1 setFrame:frameLeft];
[page2 setFrame:frameRight];
[page3 setFrame:frameCurrent];
}
[self hideShowView:page1];
[self hideShowView:page2];
[self hideShowView:page3];
}
}
}
/**
* This method hides the view if it is outside the scrollview content bounds, i.e. the
* view before page 0, or the view after last page.
*/
-(void)hideShowView:(NewsPage*)aPage{
if(aPage.frame.origin.x<0 || aPage.frame.origin.x>=[newsPagesView contentSize].width )
aPage.hidden = YES;
else{
aPage.hidden = NO;
}
}

Checkout my example, branch:new
https://github.com/iSevenDays/RecyclingScrollView

Related

The UIWindow's background application is jumping at the top of views when I switch from a view content to a UITableView

I am in charge to update an application in IOS8. But I have a problem when I want to switch between two view (the old and the new). The background of the UIWindow's Application jumped. It appears during 1 second and disappear. I can not find the issue. I tap on a backButton to change the content view.
- (void)onBackTap
{
NSLog(#"Standard back");
[self goBackWithAnimation:AnimatePushFromLeft];
}
- (void)goBackWithAnimation:(GraphNavigationAnimation)animation
{
NSLog(#"History Before ---> %#", [self currentHistory]);
[[self currentHistory] removeLastObject];
NSLog(#"History After ---> %#", [self currentHistory]);
self.currentVC = [[self currentHistory] lastObject];
[view_ switchContentViewTo:currentVC_.view
navigationItemStack:[[self currentHistory] valueForKey:#"navigationItem"]
isNavbarVisible:navbarVisible_
animation:animation];
}
Thank you for your support if you have already found a solution.
This is my procedure to switch from an old and a new contentView:
-(void)switchContentViewTo:(UIView *)newView navigationItemStack:(NSArray*)navigationItemStack isNavbarVisible:(BOOL)isNavbarVisible animation:GraphNavigationAnimation)animation {
BOOL isPrevNavbarVisible = navbarVisible_;
navbarVisible_ = isNavbarVisible;
if (!contentView_) {
contentView_ = newView;
[self insertSubview:contentView_ belowSubview:navbar_];
[navbar_ setItems:navigationItemStack animated:NO];
[self setNeedsLayout];
return;
}
if (newView == contentView_) {
[navbar_ setItems:navigationItemStack animated:NO];
return;
}
CGRect const bigFrame = self.bounds;
CGRect const smallFrame = CGRectMake(0, navbarHeight_,
self.bounds.size.width, self.bounds.size.height - navbarHeight_);
CGRect centerFrame = isNavbarVisible
? smallFrame
: bigFrame;
void (^step1)(void) = ^{
CGRect newViewStartFrame;
switch (animation) {
case AnimatePushFromRight: {
newViewStartFrame = CGRectOffset(centerFrame, contentView_.bounds.size.width, 0);
break;
}
case AnimatePushFromLeft: {
newViewStartFrame = CGRectOffset(centerFrame, -contentView_.bounds.size.width, 0);
break;
}
default:
newViewStartFrame = centerFrame;
break;
}
navbar_.hidden = !isNavbarVisible && !isPrevNavbarVisible;
if (isNavbarVisible && !isPrevNavbarVisible) {
navbar_.frame = CGRectMake(newViewStartFrame.origin.x, 0,
newViewStartFrame.size.width, navbarHeight_);
}
newView.frame = newViewStartFrame;
[self insertSubview:newView belowSubview:navbar_];
self.userInteractionEnabled = NO;
animating_ = YES;
};
void (^step2)(void) = ^{
CGRect oldViewFinishFrame;
switch (animation) {
case AnimatePushFromRight: {
oldViewFinishFrame = CGRectOffset(
contentView_.frame, -contentView_.bounds.size.width, 0);
break;
}
case AnimatePushFromLeft: {
oldViewFinishFrame = CGRectOffset(
contentView_.frame, contentView_.bounds.size.width, 0);
break;
}
default:
oldViewFinishFrame = contentView_.frame;
break;
}
if (!isNavbarVisible && isPrevNavbarVisible) {
navbar_.frame = CGRectMake(oldViewFinishFrame.origin.x, 0,
oldViewFinishFrame.size.width, navbarHeight_);
} else {
navbar_.frame = CGRectMake(centerFrame.origin.x, 0,
centerFrame.size.width, navbarHeight_);
}
newView.frame = centerFrame;
contentView_.frame = oldViewFinishFrame;
};
void (^step3)(void) = ^{
[contentView_ removeFromSuperview];
contentView_ = newView;
self.userInteractionEnabled = YES;
animating_ = NO;
};
[navbar_ setItems:navigationItemStack animated:(animation != AnimateNone)];
step1();
[UIView animateWithDuration:(animation != AnimateNone ? animationDuration : 0)
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
step2();
}
completion:^(BOOL finished){
step3();
}];
}

UIViewController called from Storyboard is nil

I am calling a view with method;
[self.storyboard instantiateViewControllerWithIdentifier:];
Yesterday, this method was working well, but after some time something happened, it has stopped working.
I am using both xCode6 beta 6 and xcode5 v5.1.1
My code is as below, here all objects of an ViewController is nil?
What is wrong with this?
(IBAction)addTemplateViewPressed:(id)sender
{
PhotoTemplateViewController *templateVC = [self.storyboard instantiateViewControllerWithIdentifier:#"photoTemplateViewController"];
//NSLog(#"%#",NSStringFromCGRect(templateVC.view.frame));
if(photoVerticalArray.count !=0 )
{
photoVerticalArray = [templateVC setVerticalImages:photoVerticalArray];
}
else
{
verticalFinished = true;
}
if(photoHorizontalArray.count !=0)
{
photoHorizontalArray = [templateVC setHorizontalImages:photoHorizontalArray];
}
else
{
horizontalFinished = true;
}
if(!verticalFinished && !horizontalFinished)
{
CGRect temp = templateVC.mainView.frame;
if(lastPosition == 0)
{
temp.origin.y = lastPosition = templateVC.mainView.frame.origin.y+48;
}
else
{
lastPosition = temp.origin.y= lastPosition + temp.size.height-4;
}
templateVC.view.frame = temp;
[mainView addSubview:templateVC.view];
NSLog(#"%#",NSStringFromCGSize(mainScrollView.contentSize));
[mainScrollView setContentSize:CGSizeMake(0, temp.origin.y+temp.size.height+50)];
NSLog(#"%#",NSStringFromCGSize(mainScrollView.contentSize));
}

shouldAutorotateToInterfaceOrientation method not called in ipad

I am trying to get the orientation of device when the device is rorate. my code is works good for iphone but for ipad shouldAutorotateToInterfaceOrientation method is not called. i have taken tab view controller as a root view controller and below code i have written on first tab's view controller.
Source Code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//[self configureForOrientation:interfaceOrientation];
return YES;
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self configureForOrientation:toInterfaceOrientation];
}
-(void)configureForOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
NSLog(#"Land");
if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
{
NSLog(#"Land ipad");
view_home.frame = CGRectMake(0,0,1004,768);
scroll_home.frame = CGRectMake(0,0,1004,768);
scroll_home.contentSize = CGSizeMake(scroll_home.frame.size.width,scroll_home.frame.size.height);
scroll_home.scrollEnabled = true;
btntitle.frame = CGRectMake(0,0,1004,52);
}
else
{
view_home.frame = CGRectMake(0,0,568,320);
status.frame = CGRectMake(0, 0, view_home.bounds.size.width, 20.0f);
scroll_home.frame = CGRectMake(0, 0, 568,430);
scroll_home.contentSize = CGSizeMake(scroll_home.frame.size.width,scroll_home.frame.size.height);
scroll_home.scrollEnabled = true;
btntitle.frame = CGRectMake(0,0,480,48);
}
}
else
{
NSLog(#"Port");
if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
{
view_home.frame = CGRectMake(0,0,768,1004);
scroll_home.frame = CGRectMake(0,0,768,1004);
//scroll_home.contentSize = CGSizeMake(scroll_home.frame.size.width,scroll_home.frame.size.height);
scroll_home.scrollEnabled = false;
btntitle.frame = CGRectMake(0,0,768,52);
}
else
{
view_home.frame = CGRectMake(0,0,320,548); //548
scroll_home.frame = CGRectMake(0, 0, 480, 568);
//scroll_home.contentSize = CGSizeMake(scroll_home.frame.size.width,scroll_home.frame.size.height);
scroll_home.scrollEnabled = false;
btntitle.frame = CGRectMake(0,0,320,48);
}
}
}

Gap bug between cells. ios6. UITableView

I have some issues with dynamic cell height. you can see it on screen. Issues highlighted in red. I haven't this issues on IOS 7.
UPD.
heightForRowAtIndexPath method seem like this:
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath {
Contact* contact = [contacts objectAtIndex: indexPath.row];
CGFloat height = 170.0f;
if (contact.name ==nil) {
height -=25.0f;
}
if (contact.phone ==nil) {
height -=25.0f;
}
if (contact.email==nil) {
height -=25.0f;
}
if (contact.address==nil) {
height -=40.0f;
}
return height;
}
But i dunno why it correctly work on iphone 5 with ios7 and not work on iphone 4 with ios6.1.
UPD2
layoutSubviews method:
-(void)layoutSubviews {
CGFloat phoneY = 65.0f;
CGFloat emailY = 90.0f;
CGFloat addressY = 115.0f;
CGRect contactNameLabelFrame = contactNameLabel.frame;
CGRect nameLabelFrame = nameLabel.frame;
CGRect phoneLabelFrame = contactPhoneLabel.frame;
CGRect phoneButtonFrame = phoneButton.frame;
CGRect emailButtonFrame = emailButton.frame;
CGRect emailLabelFrame = contactEmailLabel.frame;
CGRect addressLabelFrame = contactAddressLabel.frame;
CGRect addressButtonFrame = addressButton.frame;
if (contact.name == nil) {
contactNameLabelFrame.size.width = 0.0f;
nameLabelFrame.size.width = 0.0f;
phoneY -=25.0f;
emailY -= 25.0f;
addressY -= 25.0f;
} else {
contactNameLabelFrame.size.width = 60.0f;
nameLabelFrame.size.width = 212.0f;
}
if (contact.phone == nil) {
phoneLabelFrame.size.width = 0.0f;
phoneButtonFrame.size.width = 0.0f;
emailY -= 25.0f;
addressY -= 25.0f;
} else {
phoneLabelFrame.size.width = 60.0f;
phoneLabelFrame.origin.y = phoneY;
phoneButtonFrame.size.width = 212.0f;
phoneButtonFrame.origin.y = phoneY - 4;
}
if (contact.email == nil) {
emailLabelFrame.size.width = 0.0f;
emailButtonFrame.size.width = 0.0f;
addressY -= 25.0f;
} else {
emailLabelFrame.origin.y = emailY;
emailLabelFrame.size.width = 60.0f;
emailButtonFrame.origin.y = emailY - 4;
emailButtonFrame.size.width = 212.0f;
}
if (contact.address == nil) {
addressLabelFrame.size.width = 0.0f;
addressButtonFrame.size.width = 0.0f;
} else {
addressLabelFrame.origin.y = addressY;
addressLabelFrame.size.width = 60.0f;
addressButtonFrame.origin.y = addressY + 2;
addressButtonFrame.size.width = 212.0f;
}
[contactNameLabel setFrame:contactNameLabelFrame];
[nameLabel setFrame:nameLabelFrame];
[contactPhoneLabel setFrame:phoneLabelFrame];
[phoneButton setFrame:phoneButtonFrame];
[contactEmailLabel setFrame:emailLabelFrame];
[emailButton setFrame:emailButtonFrame];
[contactAddressLabel setFrame:addressLabelFrame];
[addressButton setFrame:addressButtonFrame];
}
UPD3
Thanks all. I found the source of the problem. I add to layoutSubviews method [super layoutSubviews];

iOS Allowing one touch event at one given time

I am using iOS 5 to implement an app.
In this app I have 4 button, each button triggers an animation to unhide a UIView. However, if I press a button and then another, the view that appeared first should disappear and the view for the new button would appear.
I have this working so far. But if the user taps two buttons rapidly it will display the two views. How can I insure that only once touch event is processed?
The action for the button is something like:
- (void)buttonPressed:(id)sender
{
MenuButton *aButton = (MenuButton *)sender;
switch (aButton.tag) {
case 0:
if (displayingView && currentlyDisplayingView != picker1)
[self toggleView:currentlyDisplayingView atIndex:currentIndex];
[self toggleView:picker1 atIndex:aButton.tag];
currentlyDisplayingView = picker1;
currentIndex = aButton.tag;
break;
case 1:
if (displayingView && currentlyDisplayingView != picker2)
[self toggleView:currentlyDisplayingView atIndex:currentIndex];
[self toggleView:picker2 atIndex:aButton.tag];
currentlyDisplayingView = picker2;
currentIndex = aButton.tag;
break;
case 2:
if (displayingView && currentlyDisplayingView != picker3)
[self toggleView:currentlyDisplayingView atIndex:currentIndex];
[self toggleView:picker3 atIndex:aButton.tag];
currentlyDisplayingView = picker3;
currentIndex = aButton.tag;
break;
default:
break;
}
NSLog(#"Pressed %#",[buttonNames objectAtIndex:aButton.tag]);
}
And the animation code:
- (void)toggleView:(UIView *)picker
atIndex:(NSInteger)index
{
if (picker) {
picker.hidden = NO;
[UIView animateWithDuration:0.5
animations:^{
picker.alpha = abs(picker.alpha - 1);
CGRect rect = picker.frame;
if (rect.size.height == 0){
rect.size.height = 76;
} else if (rect.size.height == 76) {
rect.size.height = 0;
}
picker.frame = rect;
for (int i = index+1; i < [viewButtons count]; i++) {
UIButton *aButton = [viewButtons objectAtIndex:i];
CGRect frame = aButton.frame;
if (rect.size.height == 0){
frame.origin.y -= 75;
} else if (rect.size.height == 76) {
frame.origin.y += 75;
}
aButton.frame = frame;
}
}
completion:^(BOOL success){
if (picker.alpha == 0){
picker.hidden = YES;
} else if (picker.alpha == 1) {
picker.hidden = NO;
}
displayingView = !displayingView;
}];
}
}
Call beginIgnoringInteractionEvents before calling animateWithDuration, and call endIgnoring... in the completion handler.

Resources