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.
Related
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 a really big problem with UIScrollView. To make sure it wasn't my actual project, I created a NEW project, iPhone only, for iOS 6 and 7. I disabled autolayout.
I created a Tab Bar project
I created a view controller,
embedded it in a navigation controller and connected it as Tab bar
item #0
I put a UIScrollView in my view.
I connected the scrollview in the custom UIViewController created for this view.
I synthesized my IBOutlet and set the delegate to self. I also
implemented delegate in .h
Here is my code (ViewDidLoad):
self.scrollView.delegate = self;
[self.scrollView setScrollEnabled:YES];
[self.scrollView setContentSize:CGSizeMake(self.view.frame.size.width, 20000)];
NSLog(#"contentSize width %f", self.scrollView.contentSize.width);
NSLog(#"contentSize height %f", self.scrollView.contentSize.height);
NSLog(#"%#", NSStringFromCGAffineTransform(self.scrollView.transform));
It returns me "contentSize width 20000.000000", "contentSize height 0.000000
" and "[1, 0, 0, 1, 0, 0]". It scrolls left-right where it should scroll up-down
Please help!
I had the same issue until I realized I hadn't set the UIScrollView delegate. Also, if you're using auto layout, you need to wait for the layout to be applied to the UIScrollView. This means you should set the Content Size in "viewDidLayoutSubviews".
In viewDidLoad method, frame may not be correct, move the code to this method:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Your code
}
Use this code. ScrollView setContentSize should be called async in main thread.
Swift:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
DispatchQueue.main.async {
var contentRect = CGRect.zero
for view in self.scrollView.subviews {
contentRect = contentRect.union(view.frame)
}
self.scrollView.contentSize = contentRect.size
}
}
Objective C:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
dispatch_async(dispatch_get_main_queue(), ^ {
CGRect contentRect = CGRectZero;
for(UIView *view in scrollView.subviews)
contentRect = CGRectUnion(contentRect,view.frame);
scrollView.contentSize = contentRect.size;
});
}
Okay, there is absolutely nothing wrong with your code. So some suggestions:
Make sure you added to your .h file like so:
#interface yourViewController : UIViewController <UIScrollViewDelegate> {
}
Try moving this snippet of code to the "viewWillLoad" method:
- (void)viewWillAppear:(BOOL)animated {
self.scrollView.delegate = self;
[self.scrollView setScrollEnabled:YES];
[self.scrollView setContentSize:CGSizeMake(self.view.frame.size.width, 20000)];
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
var contentRect = CGRect.zero
for view: UIView in scrollView.subviews {
if !view.isHidden {
contentRect = contentRect.union(view.frame)
}
}
scrollView.contentSize = contentRect.size
scrollView.contentSize.width = self.view.frame.width
}
Working Swift 3.X code. Converted #Karen Hovhannisyan's answer.
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 ;)
I'm creating a "how-to"view where I show the user 5-6 pictures on how to use the app. I want it to be like a container inside the real view. Also I want it to have a transition with swipe and a page control. Something like the AppStore has on the pictures with screenshots of an app if you know what I mean?
Is there an easy way to do this? All help highly appreciated!
here a simple code, but you can customize it with loop, animation or what you want to do ;) ...
- (void)viewDidLoad
{
[super viewDidLoad];
//init scollview
scrollView = [[UIScrollView alloc] initWithFrame:myBounds];
scrollView.delegate = self;
scrollView.pagingEnabled = YES;
//Ajout des covers classiques
for (int i = 0; i < [myCovers count]; i++) {
CGRect frame;
frame.origin.x = scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = scrollView.frame.size;
//Vue 1
UIView *subview1 = [[UIView alloc] initWithFrame:frame];
[subview1 addSubview:[myCovers objectAtIndex:i]];
[scrollView addSubview:subview1];
}
//Content Size Scrollview
scrollViewBack.contentSize = CGSizeMake(scrollViewBack.frame.size.width * ([myCovers count]), scrollViewBack.frame.size.height);
[self.view addSubview:scrollViewBack];
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*([myCovers count]), scrollView.frame.size.height);
[self.view addSubview:scrollView];
//Page Control
pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, scrollView.frame.size.height - PAGECONTROL_HEIGTH - myBaseline, scrollView.frame.size.width, PAGECONTROL_HEIGTH)];
pageControl.numberOfPages = [myCovers count];
[self.view addSubview:pageControl];
}
#pragma mark -
#pragma mark Params setting
- (void) setObjects:(NSArray *)covers {
myCovers = [[NSArray alloc] initWithArray:covers];
}
#pragma mark -
#pragma mark Scrollview delegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender {
CGFloat pageWidth = scrollView.frame.size.width;
NSInteger offsetLooping = 1;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + offsetLooping;
pageControl.currentPage = page % [myCovers count];
}
You can create UIImageView for the 'n' number of images you have.
Add this images on UIScrollView. Keep the size of your scrollview same as your UIImageView size.
Most important thing, enable the Paging property of UIScrollView
It should give you the look same as AppStore screen
shot screen.
first take a look on this picture from localScope app :
i have 2 (simple?) questions :
how can i paginate my icons like this?
how can i detect witch icon is " selected "
thank you.
Answer to the first question: You have to make your scroll view as big as the page size, enable its pagingEnabled property, then somehow make it to display elements and respond to touches outside of its bounds. See this code and these links:
#interface SmallPagedScrollView: UIScrollView <UIScrollViewDelegate> {
UIEdgeInsets responseInsets;
NSMutableArray *items;
}
#implementation SmallPagedScrollView
#synthesize responseInsets;
- (id)init
{
if ((self = [super initWithFrame:CGRectMake(x, y, w, h)]))
{
self.backgroundColor = [UIColor clearColor];
self.pagingEnabled = YES;
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
self.clipsToBounds = NO;
CGFloat hInset = 3 * self.width / 2;
self.responseInsets = UIEdgeInsetsMake(0.0f, hInset, 0.0f, hInset);
self.delegate = self;
items = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc
{
[items release];
[super dealloc];
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint parentLocation = [self convertPoint:point toView:self.superview];
CGRect responseRect = self.frame;
responseRect.origin.x -= self.responseInsets.left;
responseRect.origin.y -= self.responseInsets.top;
responseRect.size.width += self.responseInsets.left + self.responseInsets.right;
responseRect.size.height += self.responseInsets.top + self.responseInsets.bottom;
return CGRectContainsPoint(responseRect, parentLocation);
}
See also Paging UIScrollView in increments smaller than frame size (Split's answer)
Answer to the second question: you can calculate the selected page using this formula:
int selectedIndex = (scrollView.contentOffset + scrollView.size.width / 2) / scrollView.size.width;
Well one clean & memory efficient approach is to have a UINavigationController & UIToolBar like so -
When the user taps on any button in the UIToolBar invoke that particular viewController by popping and pushing them.
I hope its clear that the look and feel can be achieved close to what you are showing in the image, I am talking about the functionality.