I am a newbie of IOS development, my problem is I am using UIScrollView and UIPageControl to show guide info to users. I created a xib file related to GuideViewController via setting up File's Owner. I setup the content size and statically add subviews in xib files. But I encountered some strange thing, scrollview only shows the first subview on screen, all following display is just white background (when I scrolling).
Following is the code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSInteger numberOfPages = 2;
self.pageControl.numberOfPages = numberOfPages;
self.pageControl.currentPage = 0;
self.pageScroll.delegate = self;
self.pageScroll.contentSize = CGSizeMake(self.view.frame.size.width * numberOfPages,
self.view.frame.size.height);
self.pageControl.currentPageIndicatorTintColor = [UIColor redColor];
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat pageWidth = self.view.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth/2) / pageWidth) + 1;
self.pageControl.currentPage = page;
}
I googled a lot to find the answer but still stuck here.
I am also confused by this sentence "When a user taps a page control to move to the next or previous page, the control sends the UIControlEventValueChanged event for handling by the delegate" in xcode help. It seems UIPageControl has no delegate attribute,so how I can capture the UIControlEventValueChanged event.
Actually I am developing my main UI on storyboard, but I kind of want separate UI design to make more space for storyboard, so i use xib file for some other part UI, I do not know whether this will cause some problems. Thanks
My solution was this:
Add a IBAction in your header:
- (IBAction)changePage;
Dont forget to set the Outlet and the property for the pageControl:
IBOutlet UIPageControl *pageControl;
#property (nonatomic, retain) IBOutlet UIPageControl* pageControl;
Add a BOOLEAN that the pagecontrol updates:
BOOL pageControlBeingUsed;
Here is my full header:
#interface ViewC : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageControl;
BOOL pageControlBeingUsed;
}
#property (nonatomic, retain) IBOutlet UIScrollView* scrollView;
#property (nonatomic, retain) IBOutlet UIPageControl* pageControl;
- (IBAction)changePage;
#end
(Don't forget to synthesize the propertys)
The second step you did already with the viewdidLoad method but you didn't connected the Boolean to the method! Try this:
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (!pageControlBeingUsed) {
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
}
}
Add at the end this code for the IBAction and that when the pageControl was pressed at a button the site changes.
- (IBAction)changePage {
// update the scroll view to the appropriate page
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
[self.scrollView scrollRectToVisible:frame animated:YES];
pageControlBeingUsed = YES;
}
IMPORTANT:
Connect the IBAction with "value changed" option in the xib. and set the delegate of the Controller to itself:
And then it should be like this:
That is all! Hope you fixed your issue. I would be glad if you give my awnser the "tick" if it helped you!
Greetings,
Noah
Related
I have a xib file which contains a UIButton. I control + dragged the button to create an action. The position of the button has to be set dynamically. The method below is called from drawRect: method which updates the button position.
-(void)updateButtonPosition {
CGFloat xPos = self.label.frame.origin.x + self.label.frame.size.width;
CGFloat yPos = self.label.frame.origin.y + self.label.frame.size.height - 25;
CGRect frame = CGRectMake(xPos, yPos, self.button.frame.size.width, self.button.frame.size.height);
self.button.frame = frame;
}
But I noticed that calling this function disconnects the UIButton from the action I created by control + dragging (i.e. nothing happens when I click the button when the app is running). I commented the part where this function was called. And now the button started working and the action method was called. So changing the frame disconnected the UIButton from its action method.
EDIT: User Interaction is enabled for all its superview. I'm not using auto layout. The project is like that.
How can I change the frame of the button so that the action is also called when I click the button?
Check the button's frame with it's superview frame. The button receives touch events only when it resides inside it's superview frame.
Can't reproduce your problem, I dragged an action named "btnAction" and a outlet named "btnTest".
This is ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (IBAction)btnAction:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *btnTest;
#end
And this is ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
// [super viewDidLoad];
// // Do any additional setup after loading the view, typically from a nib.
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(grHandler)]];
}
-(void)grHandler{
NSLog(#"grHandler actived.");
[self updateButtonPosition];
}
- (IBAction)btnAction:(id)sender {
NSLog(#"btn actived.");
}
-(void)updateButtonPosition {
CGFloat xPos = 20;
CGFloat yPos = 30;
CGRect frame = CGRectMake(xPos, yPos, self.btnTest.frame.size.width, self.btnTest.frame.size.height);
self.btnTest.frame = frame;
}
#end
Try to use my code and tell me where is the problem?
Then I can help you.
My button's frame was outside the frame of its parent view. Hence it was not tap able.
For more info refer UIButton not responding after set frame within UIScrollview
I create a demo for checking UITextView scrollEnabled.
It only contains 1 UITextView and 2 button enable and disable scroll
I test on simulator and device iOS 8, if I click the disable scroll button, the UITextView will disable scroll correctly, but after that I
click on enable scroll, the UITextView won't enable scroll
However, I test on device iOS9, the enable and disable scroll work well.
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITextView *myTextView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)enableScrollButtonPressed:(id)sender{
self.myTextView.scrollEnabled = YES;
}
- (IBAction)disableScrollButtonPressed:(id)sender{
self.myTextView.scrollEnabled = NO;
}
#end
Any idea to fix this problem? If someone don't understand my explain please check
my demo project
Any help or suggestion would be great appreciated
The problem is that in iOS 8, contentSize is not adjusted correctly when scrollEnabled is changed. A small adjustment to your enableScrollButtonPressed method will successfully work around the problem.
-(IBAction)enableScrollButtonPressed:(id)sender
{
self.myTextView.scrollEnabled = YES;
self.myTextView.contentSize = [self.myTextView sizeThatFits:self.myTextView.frame.size];
}
Yeah you are right disabling and enabling scroll of textview is not working in iOS8 it may be a bug or anything else, let it be.
We can disable or enable scroll of text view by just changing the ContentSize of textview .
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITextView *myTextView;
#end
#implementation ViewController
-(IBAction)enableScrollButtonPressed:(id)sender{
CGSize scrollableSize = CGSizeMake(self.myTextView.bounds.size.width+20, self.myTextView.bounds.size.height+20);
[self.myTextView setContentSize:scrollableSize];
}
-(IBAction)disableScrollButtonPressed:(id)sender{
[self.myTextView setContentOffset:CGPointMake(0, 0)];
[self performSelector:#selector(StopScroll) withObject:nil afterDelay:0.1];
}
-(void)StopScroll{
CGSize scrollableSize = CGSizeMake(self.myTextView.bounds.size.width, self.myTextView.bounds.size.height/2);
[self.myTextView setContentSize:scrollableSize];
}
#end
I had tested the above code it is working fine for me i'am using xcode 7.2.1 and iOS 8.3. Give it a try and let me know the result
After searching hours i am found one way
-(IBAction)enableScrollButtonPressed:(id)sender{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.myTextView.scrollEnabled = YES;
[self.myTextView setText:self.myTextView.text];
self.myTextView.layoutManager.allowsNonContiguousLayout = false;
});
}
-(IBAction)disableScrollButtonPressed:(id)sender{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.myTextView.scrollEnabled = NO;
});
}
condition for that is you need to scroll first then you it will work perfectly
Means when disable scroll button is tapped textview should be scrolled at some position must not to at default position
Please follow below steps simply
self.myTextView.scrollEnabled = NO;
self.myTextView.userInteractionEnabled = YES;
self.myTextView.scrollEnabled = YES;
you need to layout your views after enabling or disabling scroll view in your view.
use viewWillLayoutSubviews/layoutIfNeeded methods.
change your property as follows.
in your code..
#property (weak, nonatomic) IBOutlet UITextView *myTextView;
change property attribute as follows:
#property (strong, nonatomic) IBOutlet UITextView *myTextView;
then it'll work fine. i checked it.
I tried my code and it worked properly
IBOutlet UITextView *tv;
//---------Enable button action.
-(IBAction)enable:(id)sender
{
tv.scrollEnabled=YES;
}
//---------Disable button action.
-(IBAction)disable:(id)sender
{
tv.scrollEnabled=NO;
}
try your code once more in device.
Try this one
func scrollViewDidScroll(_ scrollView: UIScrollView) {
tableView.setContentOffset(CGPoint.zero, animated: false)
}
I'm Making a game, with level select Ive got 3 levels and 3 views on 3 different controllers
Now I've placed 2 - 1/4 of the button on each side of my scroll view, on on the left and one on the right!
When the user of the game is on level 1 "thats View1" The button on the left needs to be hidden and only show when its on View2 and View 3 - same goes for the button on View3 on the right!
How is this done?
Outlets for those buttons are leftIllusion & rightIllusion
code for UIViews:
#implementation ViewController
#synthesize View1;
#synthesize View2;
#synthesize View3;
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"View1"]];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"View2"]];
[self addChildViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"View3"]];
}
code from that imports scroll file .h:
#import "PagerViewController.h"
#interface ViewController : PagerViewController {
}
#property (strong, nonatomic) IBOutlet UIView *View1;
#property (strong, nonatomic) IBOutlet UIView *View2;
#property (strong, nonatomic) IBOutlet UIView *View3;
#end
UIScrollView instance has property contentOffset, which can help you to detect what view is being displayed now (view1, view2, view3). I am posting example code-snippet, which helps me to determine the page number of scrollView.
- (NSInteger)pageNumber
{
static NSInteger previousPage = 0;
CGFloat pageWidth = self.scrollView.frame.size.width;
float fractionalPage = self.scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
NSLog(#"page number %d",page);
if (previousPage != page) {
previousPage = page;
/* Page did change */
//put here your hide/show buttons logics
}
return page;
}
The best place to insert these lines is scrollView delegate's method -(void)scrollViewDidEndDecelerating:. The scroll view calls this method each time when the scrolling movement comes to a halt.
So your final version will look like:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender
{
[self pageNumber];
}
I have a UIViewController,which is associated with custom class MAViewControllerMenu and loads right after the splash screen. In that UIViewController, I have an UIScrollView, which belongs to another class, MASlideShowView, in which the IBOutlet of the UIScrollView is defined and is connected to.
The class for the UIViewController has, among others, the field:
#property MASlideShowView* slideShow;
as a private property for the class that holds the UIScrollView inside it.
Also in the UIViewController,
- (void)viewDidLoad
{
[super viewDidLoad];
//TODO [_slideShow initializeImages];
_slideShow = [[MASlideShowView alloc] initWithModel];
_slideShow.delegate = imageViewController;
}
- (void)viewDidAppear{
[super viewDidAppear:(YES)];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Set up the content size of the scroll view
//HERE, self.slideShow is allocated, but all the fields it has, including the IBOutlet to the UIScrollView is still nil
CGSize pagesScrollViewSize = self.slideShow.frame.size;
_slideShow.contentSize = CGSizeMake(pagesScrollViewSize.width * self.pageViews.count, pagesScrollViewSize.height);
//Delegate
_slideShow.scrollView.delegate = self;
// Load the initial set of pages that are on screen
[_slideShow loadVisiblePages:YES page_index:0 image:_last_image_taken];
}
Note the error I saw in the comments in the above class
The MASlideShowView file looks like:
h:
#class MASlideShowView;
#protocol slideShowDelegate <NSObject>
-(void)imageViewSelected:(MASlideShowView*)slideShow image:(UIImage*)image;
#end
#interface MASlideShowView : UIScrollView
#property (nonatomic,weak) id<slideShowDelegate> delegate;//delegate to next controller to notify upon picture centered
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
#property (nonatomic, strong) IBOutlet UIPageControl *pageControl;
#property (weak, nonatomic) IBOutlet UIButton *rotateImageButton;
#property UIImageView* centered_image_view;
- (IBAction)PageThroughPageControl;
- (IBAction)rotateImageButtonClicked;
- (id)initWithModel;
- (void)pageThroughPageControl;
- (void)addImageToSlideshow:(UIImage*)toAdd;
- (void)loadVisiblePages:(BOOL)use_page_number page_index:(NSInteger)page image:(UIImage*)image;
#end
m:
- (id)initWithModel{
[self initializeImages];
return self;
}
-(void)initializeImages{
// Set up the image you want to scroll & zoom and add it to the scroll view
self.pageViews = [NSMutableArray arrayWithObjects:nil];
NSInteger pageCount = 0;
_imageViewCount = 0;
// Set up the page control
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
// Set up the array to hold the views for each page
self.pageViews = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < pageCount; ++i) {
[self.pageViews addObject:[NSNull null]];
}
}
My question is simple:
How can I make the UIScrollView initialize?
I know that there's no viewDidAppear as it inherits from UIScrollView.
Thanks
As you are using Interface Builder, I would recommend calling initializeImages inside awakeFromNib:
An awakeFromNib message is sent to each object loaded from the
archive, but only if it can respond to the message, and only after all
the objects in the archive have been loaded and initialized. When an
object receives an awakeFromNib message, it is guaranteed to have all
its outlet instance variables set.
More details here.
Other observations:
As for your code, you have slideShow correctly set by Interface Builder when entering viewDidLoad but you're replacing that instance by assigning _slideShow = [[MASlideShowView alloc] initWithModel], which results in a completely different object.
Moreover your initWithModel doesn't look at all like a correct init method as it doesn't call any of its super's init methods. You should start with Apple's snippet by writing init in an empty line and press escape:
Again the first paragraph of the answer should be enough for your problem.
There's a few ways you could go about fixing this.
One way is like #HoanNguyen mentioned to use awakeFromNib. Personally I don't use this but it's a valid lifecycle event for setup.
Another option is to override initWithCoder: which is the standard initializer storyboards use
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self) {
[self initializeImages];
}
return self;
}
You could then remove your initWithModel call and the storyboard should handle everything.
I have a ScrollView in which there are 10 viewControllers I have added each ViewController and it contaning two button Yes and No Button. Yes Button take you to the next screen or ViewController.
My page is swiping well but whenever i perform an action through yes button , i am able to go to the next screen but my page swipe is not working anymore.
what i wanted is that if yes button action is performed then swipe of page is done in correct way?
#interface PagerViewController : UIViewController <UIScrollViewDelegate>
#property (nonatomic, strong) IBOutlet UIScrollView *scrollView;
#property (nonatomic, strong) IBOutlet UIPageControl *pageControl;
-(IBAction)changePage:(id)sender;
- (void)previousPage;
- (void)nextPage;
I don't know what you have done inside changePage: but if you have done something like this, then your scrollview page swipe should work fine.
- (void)gotoPage
{
NSInteger page = // page you want to go to;
// update the scroll view to the appropriate page
CGRect bounds = self.scrollView.bounds;
bounds.origin.x = CGRectGetWidth(bounds) * page;
bounds.origin.y = 0;
[self.scrollView scrollRectToVisible:bounds animated:NO];
}
You can call above function inside your changePage: method.
I'm not sure but I wish It could help you,See here, You should use UIPageViewControleller which has been provided by Apple. Here Check out Apple Docs. Happy Coding!