I am trying to pull down a UIView (Like a Pull Down Menu) when the user scrolls below a Y-offset of 0.0 in the UITable View. If the user pulls down below -80.0 Y-Offset, then the PullDownMenu locks itself , until the User scrolls the other way.
My implementation for just the UITableView's ScrollView is as follows : [lock:false initially]
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
if(isChangingOffset)
return;
if(resetDrag)
{
[self setScrollViewOffset:scrollView offsetTo:CGPointMake(0, -80.0)];
resetDrag = false;
}
float xx = scrollView.contentOffset.y;
NSLog(#"Offset :%f",xx);
if(xx - begginOffset > 0.0 && lock && !doneDragging)
{
offsetChange = xx - begginOffset;
begginOffset = xx;
lock = false;
[self setScrollViewOffset:scrollView offsetTo:CGPointMake(0, -80.0)];
}
if(lock){
[self setScrollViewOffset:scrollView offsetTo:CGPointMake(0, -80.0)];
}
if(xx <=-80.0)
{
[self setScrollViewOffset:scrollView offsetTo:CGPointMake(0, -80.0)];
lock = true;
}
}
- (void)setScrollViewOffset:(UIScrollView *)scrollView offsetTo:(CGPoint)offset{
- (void)setScrollViewOffset:(UIScrollView *)scrollView offsetTo:(CGPoint)offset{
isChangingOffset = true;
scrollView.contentOffset = CGPointMake(0, -80.0);
isChangingOffset = false;
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
float x = scrollView.contentOffset.y;
begginOffset = x;
doneDragging = false;
if(lock){
resetDrag = true;
}
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
doneDragging = true;
}
Here is a working video of how it looks : Video
The blue color is a UIView that I have added as a subview in the UITableView.
My problem is , I am trying to pull down a UIView,lets call it menuView (that is not a subview of the tableView) based on the UITableView's contentOffset. I could have simply added the menuView in the UITableView like I added the blue color view. But that is only accessible via the table, that is when I scroll to the top and drag it down. But I want the menuView to be 'pull-able' like the notification center at any time.
On using the Y-contentOffset of scroll view, the menuview pull down animation is not smooth. And it stops midway or goes too low. It is jerky and not always the same. How can I implement this ?
Here the sample code for your UIScrollView :
ViewController.h
#interface ViewController: UIViewController {
UIScrollView *scrollView;
}
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
ViewController.m
#implementation ViewController
#synthesize scrollView;
- (void)viewDidLoad
{
[super viewDidLoad];
[self scrollView];
}
- (void)scrollText{
[scrollView setContentSize:CGSizeMake(320, 800)];
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
scrollView.clipsToBounds = YES;
}
And iside you can put wat you want, from code or interface builder.
For a PullDownMenu you can see this GitHub:
MBPullDownController
Hope this help you and simplify your code ;)
Related
I have 2 VCs on my UIPageViewController.
I want that if the user is on the 1st view, he won't be able to swipe to the right (just to the left - to the 2nd view), and if he's on the 2nd view he won't be able to swipe to the left (just to the right - to the 1st view).
I want that the user won't be able to scroll - not a black view (what happens when I return nil on: - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController)
The "black view" is likely to be the background of your main view, or the background colour of your UIPageViewController.
You can kill scrolling in one of the directions depending on the ViewController that the PageViewController is currently showing
first set your VC as the delegate for the PageViewController's inner scroll view. You can add a more sophisticated subviews traversal here, this is a simple version:
for (UIView *view in self.pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
[(UIScrollView *)view setDelegate:self];
}
}
then add a property to your VC as this:
#property (nonatomic) CGPoint lastOffset;
and after that implement the following scroll view delegate methods
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES;
self.lastOffset = scrollView.contentOffset;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint nowOffset = scrollView.contentOffset;
NSLog(#"delta %f", self.lastOffset.x - nowOffset.x);
if ((self.lastOffset.x - nowOffset.x) < 0) {
//uncomment to prevent scroll to left
//scrollView.scrollEnabled = NO;
} else if ((self.lastOffset.x - nowOffset.x) > 0) {
//uncomment to prevent scroll to right
//scrollView.scrollEnabled = NO;
} else {
scrollView.scrollEnabled = YES;
}
}
I have a scroll view which contain a view and view have five images in want a pagecontrol to show the navigation status but the page control hides behind the images. I tried everything searched internet but cant fined anything.
Implementation.h
#interface ScrollSecondViewController : UIViewController
{
IBOutlet UIView *scrContentSizeView;
IBOutlet UIScrollView * scrollView;
}
#property (nonatomic, weak) IBOutlet UIPageControl *pageControl;
#end
Implementation.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationItem setTitle:#"Scroll View"];
scrollView.contentSize = CGSizeMake(scrContentSizeView.frame.size.width, scrollView.frame.size.height);
scrollView.clipsToBounds = YES;
[scrollView setContentOffset:CGPointMake(750, 0) animated:YES];
// Do any additional setup after loading the view.
}
- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
_pageControl.currentPage = scrollView.contentOffset.x / scrollView.frame.size.width;
}
In the viewDidLoad method you should add the following code as the last method you call after adding all subviews.
- (void)viewDidLoad {
[super viewDidLoad];
//do what u want
//this should be last
[self.view bringSubviewToFront:self.pageControl];
}
I did search first, and have seen somewhat similar issues, but no definitive answer on how to solve it. The problem I'm having with my app is that I have 3 navigation controllers that are added as child view controllers into a UIScrollView. I originally wanted to use a UIPageViewController instead, but that turned out to be a mess since you can't disable the bouncing on it. For each navigation controller, a tableView controller is embedded within it in storyboard.
viewDidAppear and viewDidDisappear are not called for my child view controllers because their views are added as subviews to the paging scroll view at runtime, and I kindof believe is why I can't figure out how to solve this.
I need each of my table view controller's to respond to the user touching the status bar for the respective tableView to scroll to the top.
Here is the code I'm using for the setup of the app's main scroll view and adding the 3 view controller's views to it:
I appreciate any help offered!
MainViewController.h
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController <UIScrollViewDelegate>
#end
MainViewController.m:
#import "MainViewController.h"
#interface MainViewController ()
#property (nonatomic, strong) UINavigationController *settings;
#property (nonatomic, strong) UINavigationController *hehTwo;
#property (nonatomic, strong) UINavigationController *hehOne;
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.settings = [self.storyboard instantiateViewControllerWithIdentifier:#"Settings"];
self.hehTwo = [self.storyboard instantiateViewControllerWithIdentifier:#"HehTwo"];
self.hehOne = [self.storyboard instantiateViewControllerWithIdentifier:#"HehOne"];
[self addChildViewController:self.settings];
[self addChildViewController:self.hehTwo];
[self addChildViewController:self.hehOne];
CGRect hehTwoFrame = self.hehTwo.view.frame;
hehTwoFrame.origin.x = 320;
self.hehTwo.view.frame = hehTwoFrame;
CGRect hehOneFrame = self.hehOne.view.frame;
hehOneFrame.origin.x = 640;
self.hehOne.view.frame = hehOneFrame;
[self.scrollView addSubview:self.settings.view];
[self.scrollView addSubview:self.hehTwo.view];
[self.scrollView addSubview:self.hehOne.view];
// Setting offset so the farthest right controller is heh One
[self.scrollView setContentOffset:CGPointMake(640,0)];
self.scrollView.delegate = self;
self.scrollView.bounces = NO;
self.scrollView.delaysContentTouches = NO;
self.scrollView.contentSize = CGSizeMake(960, self.view.frame.size.height);
self.scrollView.scrollsToTop = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat width = scrollView.frame.size.width;
NSInteger page = (scrollView.contentOffset.x + (0.5f * width)) / width;
if (page == 0)
{
// Settings
}
else if (page == 1)
{
// Heh Two
}
else
{
// Heh One
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
First of all, you need to set self.tableView.scrollsToTop = NO; on HehTwo and HehOne (if these two are initially hidden) in their viewDidLoad implementation.
And now, update this method:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat width = scrollView.frame.size.width;
NSInteger page = (scrollView.contentOffset.x + (0.5f * width)) / width;
if (page == 0)
{
// Settings
((UITableViewController *)self.settings.viewControllers[0]).tableView.scrollsToTop = YES;
((UITableViewController *)self.hehOne.viewControllers[0]).tableView.scrollsToTop = NO;
((UITableViewController *)self.hehTwo.viewControllers[0]).tableView.scrollsToTop = NO;
}
else if (page == 1)
{
// Heh Two
((UITableViewController *)self.settings.viewControllers[0]).tableView.scrollsToTop = NO;
((UITableViewController *)self.hehOne.viewControllers[0]).tableView.scrollsToTop = NO;
((UITableViewController *)self.hehTwo.viewControllers[0]).tableView.scrollsToTop = YES;
}
else
{
// Heh One
((UITableViewController *)self.settings.viewControllers[0]).tableView.scrollsToTop = NO;
((UITableViewController *)self.hehOne.viewControllers[0]).tableView.scrollsToTop = YES;
((UITableViewController *)self.hehTwo.viewControllers[0]).tableView.scrollsToTop = NO;
}
}
That's all! This should fix it.
I have some images I'm trying to load within a scroll view similar to apple's page control example. My app crashes with an error of
'NSInvalidArgumentException', reason: '-[TutorialViewController
loadScrollViewWithPage:]: unrecognized selector sent to instance
0x687d0b0'
I think I understand enough of this that it's telling me that I don't have a method for the selector... but I'm not sure how to fix it! Thank you in advance.
Header File
//TutorialViewController.h
#import
#interface TutorialViewController : UIViewController <UIScrollViewDelegate>
{
// To be used when scrolls originate from the UIPageControl
BOOL pageControlUsed;
int pageNumber;
}
#property (nonatomic, retain) NSArray *iPhoneTutorial;
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
#property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
#property (nonatomic, retain) NSMutableArray *viewControllers;
- (IBAction)changePage:(id)sender;
#end
Implementation File
//TutorialViewController.m
#import "TutorialViewController.h"
static NSUInteger kNumberOfPages = 3;
static NSString *NameKey = #"nameKey";
static NSString *ImageKey = #"imageKey";
#interface TutorialViewController (PrivateMethods)
- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;
#end
#implementation TutorialViewController
#synthesize scrollView, pageControl;
- (void)awakeFromNib
{
// load our data from a plist file inside our app bundle
NSString *path = [[NSBundle mainBundle] pathForResource:#"iPhoneTutorial" ofType:#"plist"];
self.iPhoneTutorial = [NSArray arrayWithContentsOfFile:path];
// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++)
{
[controllers addObject:[NSNull null]];
}
//self.viewControllers = controllers;
//[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageControl.numberOfPages = kNumberOfPages;
pageControl.currentPage = 0;
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
//
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
}
// load the view nib and initialize the pageNumber ivar
- (id)initWithPageNumber:(int)page
{
pageNumber = page;
return self;
}
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
if (pageControlUsed)
{
// do nothing - the scroll was initiated from the page control, not the user dragging
return;
}
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// A possible optimization would be to unload the views+controllers which are no longer visible
}
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender
{
int page = pageControl.currentPage;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
pageControlUsed = YES;
}
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You have to add an
- (void)loadScrollViewWithPage:(int)page
method where you add your view
like
switch(page) {
case 0:
myView1 = [[MyView1ViewController alloc] initWithNibName:#"MyView1ViewController" bundle:nil];
[scrollView addSubview: myViewPage1.view];
break;
}
But the Apple Demo "PageControl" has such a method in File PhoneContentViewController.m
My program doesnt even go into the scrollViewDidScroll method. I have no idea why. My view did load looks like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Set the size of the content to be displayed
self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width * ScrollViewControllerNumberOfPages, self.scrollView.bounds.size.height);
// Turn on paging in the scroll view (can also be done in Interface Builder)
self.scrollView.pagingEnabled = YES;
NSLog(#"CurrentPage ViewDidLoad%#",self.pageControl.currentPage);
switch (self.pageControl.currentPage)
{
case 1:
[self.minkyImageView setImage:[UIImage imageNamed:#"monkey_1.png"]];
NSLog(#"case1");
break;
case 2:
[self.minkyImageView setImage:[UIImage imageNamed:#"Shape1.png"]];
NSLog(#"case2");
break;
default:
break;
}
}
Also i have implemented the scrollviewDelegate on my interface like this. I don't see what i am doing wrong. It doesn't even go into the method called scrollViewDidScroll.
#interface MinkyScreenSwapViewController: UIViewController <UIScrollViewDelegate>
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat contentWidth = scrollView.bounds.size.width;
CGFloat halfContentWidth = contentWidth / 2;
NSInteger currentPage = (scrollView.contentOffset.x + halfContentWidth) / contentWidth;
self.pageControl.currentPage = currentPage;
NSLog(#"CurrentPage");
}
Try out:
self.scrollView.delegate = self;
Hope this helps.
Try these codes
scrollView.delegate = self;
scrollView.userInteractionEnabled=YES;
If you are adding scroll view over image view, you have to explicitly set
imageView.userInteractionEnabled=YES;
For more convenience set
[[scrollView superView] setUserInteractionEnabled:YES];
These will make your scrollView delegate method active.