I'm trying to work with a page control. This is what I did. I've added one onto my view in the storyboard.
Then in my ViewDidLoad
images = [[NSMutableArray alloc]initWithObjects:[UIImage imageNamed:#"img1.jpg"],[UIImage imageNamed:#"img2.jpg"],[UIImage imageNamed:#"img3.jpg"],[UIImage imageNamed:#"img4.jpg"], nil];
pagecontrol = [[UIPageControl alloc]init];
self.imageIndex = 0;
[pagecontrol setNumberOfPages:images.count];
[pagecontrol setCurrentPage:imageIndex];
Like you can see I have an array of four images. I've added a pagecontrol onto an imageview. I also added two swipe gestures onto the imageView (Left and right). What I want to do now is that when I swipe:
The image is changed
The dot is updated with the correct position in the array
This is my code for right swipe:
- (void)next:(UITapGestureRecognizer *)recognizer {
if(imageIndex == images.count-1){
imageIndex = images.count-1;
}else{
imageIndex++;
}
[UIView transitionWithView:self.imgGallery
duration:1.0f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.imgGallery.image = [images objectAtIndex:imageIndex];
} completion:nil];
[pagecontrol setCurrentPage:imageIndex];
}
Problem
My images are changing properly. But my pagecontrol dot is not updating and also it is showing only 3 dots.
Can anybody help ?
enable paging in scrollview
[self.scrollView setPagingEnabled:YES];
Set delegate to your scrollview
where You define A pageControll
[_tutorialPageControll addTarget:self action:#selector(changPage) forControlEvents:UIControlEventValueChanged];
_tutorialPageControll.currentPage = 0;
_tutorialPageControll.numberOfPages = TutorialArray.count;
and in where You want a Chang thepage
_tutorialPageControll.currentPage = imageIndex;
Related
I want to have precise control over the custom view I add to my UINavigationController toolbar. More specifically.. i want to display a UILable ontop of the items in my toolbar.
I have a toolbarItems initially set up with some UIBarButtonItems. The effect I'm trying to achieve is programmatically expand the height of the toolbar, and then display a UILabel ontop of the rest of the buttons.. this is what I currently have:
-(void)expandToolBar:(NSString *)title {
UIToolbar* toolBar =self.navigationController.toolbar;
CGRect toolbarFrame = toolBar.frame;
[UIView animateWithDuration:0.25f delay:0
options:UIViewAnimationOptionLayoutSubviews animations:^{
// expand toolbar frame vertically
[toolBar setFrame:
CGRectMake(toolbarFrame.origin.x,
toolbarFrame.origin.y-15,
toolbarFrame.size.width,
toolbarFrame.size.height + 15)];
} completion:^(BOOL finished){
[UIView animateWithDuration:0.50f animations:^{
// some code here to move the existing toolbar items lower
// ie to make space for the label
UILabel* label = [[UILabel alloc] initWithFrame:labelFrame];
[label setBackgroundColor:[UIColor clearColor]];
label.text = title;
UIBarButtonItem *labelItem = [[UIBarButtonItem alloc]
initWithCustomView:label];
// add label to toolbar
NSMutableArray *newItems = [self.toolbarItems mutableCopy];
[newItems addObject:labelItem];
self.toolbarItems = newItems;
}];
}];
}
the result of this is that all the existing buttons get squashed, and the label takes their place. The problem is that If I try to get a little too creative and start manually messing with the subviews of the toolbar, I start wandering into undocumented API land, something Apple won't tolerate. Ideas?
What's your actual question? If what you're doing is legal or not? I use some similar tricks to get from the UIBarButtonItem to the view that is represented from it, and it has never been a problem.
For example, I use following snippet without any issues. Technically this isn't using private API per so, but relying on undocumented view structure and here also part of the class names, so you really should know what you're doing. Please also file a radar that UIBarButtonItem is messed up and misses an obvious flag to get to the actual view.
static UIView *PSToolbarViewForBarButtonItem(UIToolbar *toolbar, UIBarButtonItem *barButtonItem) {
UIView *barButtonView = nil;
for (UIControl *subview in toolbar.subviews) {
if ([NSStringFromClass([subview class]) hasPrefix:#"UIToolbarB"] && [subview isKindOfClass:[UIControl class]]) {
for (UIBarButtonItem *aBarButtonItem in [subview allTargets]) {
if (barButtonItem == aBarButtonItem) { barButtonView = subview; break; }
}
}
}
return barButtonView;
}
Also, if you go that route, write code that will fail gracefully if for any reason the view for the toolbar can't be found. I know some apps that go my route, while lots of others don't even bother and simply write their own code to create a toolbar.
I've a UIScrollView of size (320,160). I'm adding some UIImageView into it, which are of size (213,160). The first UImageView starting from 54 (x) and so on, I've added a space of 5.0 in between each UIImageView. I've also enabled pagingEnable in IB & in coding. What my problem is its not properly working as per its property! When I scroll it should show me UIImageViews in each single page instead it showing me something like see screenshot I want output something like this see output screenshot
Where I'm doing wrong? I also having function of< (previous) & > (next) there to show images. I've asked one question yesterday which was I accepted however my requirement is little change and it won't become my solution. see my question.
Is there any special property that I've to set, or some logic I should implement? All examples I've checked and tried but I find that my requirement is some special. Point me! Thanks.
EDITED:
- (void) setImages
{
CGFloat contentOffset = 0.0f;
for (int i=0; i<[arrImgUrls count]; i++)
{
CGRect imageViewFrame = CGRectMake(contentOffset, 0.0f, 213, scrollImages.frame.size.height);
AsyncImageView *asyncImageView = [[AsyncImageView alloc] initWithFrame:imageViewFrame];
[asyncImageView.layer setMasksToBounds:YES];
NSString *urlImage = [arrImgUrls objectAtIndex:i];
NSURL *url = [NSURL URLWithString:urlImage];
[asyncImageView loadImageFromURL:url];
[scrollImages addSubview:asyncImageView];
contentOffset += asyncImageView.frame.size.width+increment;
[asyncImageView release];
}
scrollImages.contentSize = CGSizeMake([arrImgUrls count] * scrollImages.frame.size.width, scrollImages.frame.size.height);
scrollImages.pagingEnabled = YES;
scrollImages.clipsToBounds = NO;
}
-(IBAction)prevImage:(id)sender
{
_currentImage--;
[btnNext setEnabled:YES];
if (_currentImage==0)
{
[btnPrev setEnabled:NO];
[scrollImages setContentOffset:CGPointMake((_currentImage*imageWidth), 0) animated:YES];
return;
}
NSLog(#"previous:mult %d inc %d current %d",_currentImage*imageWidth,increment*_currentImage,_currentImage);
int nextImage=_currentImage+2;
[scrollImages setContentOffset:CGPointMake((((_currentImage*imageWidth)-(increment*_currentImage)))+(nextImage*increment), 0) animated:YES];
}
-(IBAction)nextImage:(id)sender
{
_currentImage++;
NSLog(#"next:mult %d inc %d current %d",_currentImage*imageWidth,increment*_currentImage,_currentImage);
[scrollImages setContentOffset:CGPointMake((_currentImage*imageWidth)+(increment*_currentImage), 0) animated:YES];
[btnPrev setEnabled:YES];
if (_imageCount-1 == _currentImage)
{
[btnNext setEnabled:NO];
}
}
Paging scroll views alway page multiples of their frame size. So in your example paging is always +320.
This behavior is good if you have content portions matching the frame of the scroll view.
What you have to do, is giving your scroll view a width of 213 and set its clipsToBounds property to NO.
After that your scroll view pages exactly how you want and you see what's left and right outside the frame.
Additionally you have to do a trick to make this left and right area delegate touches to the scroll view.
It's greatly explained in this answer.
You are forgetting to set scrollview content size.
make sure that you have set the content size to fit N number of images.
if you want to scrollview to scroll for 10 images with an image on each page
set scrollView contentSize as
[scrollView setContentSize:CGSizeMake(320 * 10,200)];
I need in my project to make the scroll an image continuously, ie from the bottom of the image once scrolled by continuing to scroll to the top should start from the base and so on, in a sort of loop, how can I do to do this?
Thanks
In this example i am taking total 5 images
- (void)viewDidLoad {
[super viewDidLoad];
// add the last image (image4) into the first position
[self addImageWithName:#"image4.jpg" atPosition:0];
// add all of the images to the scroll view
for (int i = 1; i < 5; i++) {
[self addImageWithName:[NSString stringWithFormat:#"image%i.jpg",i] atPosition:i];
}
// add the first image (image1) into the last position
[self addImageWithName:#"image1.jpg" atPosition:5];
scrollView.contentSize = CGSizeMake(320, 2496);
[scrollView scrollRectToVisible:CGRectMake(0,416,320,416) animated:NO];
}
- (void)addImageWithName:(NSString*)imageString atPosition:(int)position {
// add image to scroll view
UIImage *image = [UIImage imageNamed:imageString];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0,position*416,320, 416);
[scrollView addSubview:imageView];
[imageView release];
}
implement delegate method
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender {
NSLog(#"%f",scrollView.contentOffset.y);
// The key is repositioning without animation
if (scrollView.contentOffset.y == 0) {
// user is scrolling to the left from image 1 to image 4
// reposition offset to show image 4 that is on the right in the scroll view
[scrollView scrollRectToVisible:CGRectMake(0,1664,320,416) animated:NO];
}
else if (scrollView.contentOffset.y == 2080) {
// user is scrolling to the right from image 4 to image 1
// reposition offset to show image 1 that is on the left in the scroll view
[scrollView scrollRectToVisible:CGRectMake(0,416,320,416) animated:NO];
}
}
I gives the two reference link for the automatically scroll the scroll view where the you can grap the source code also and implement into your project it's amazing funcationality
1) Automatically scroll the scroll view
2) As par your requirement created post of like wise gallery.
May this post is useful for you.
Happy codeing
Thanks and Regards,
#Samuel
Basically, I want to have an app with only one view that has an image on it. I want to be able to swipe left or right and have the first image go out of the view and the second image to come in. The images are the same and I want it to look like they are connected (like scrolling down a rope where the pattern just repeats, but it looks like a constant scroll). I need it to be able to change the image or restart after a series of swipes. I know that I need to turn pagination ON in the UIScrollView, but I am new to iOS and am having trouble.
Ultimately, I want to have the iPhone vibrate every so-and-so swipes (and restart the pattern).
I'm sure that there are a lot of ways to do this (i.e. a TableView) so feel free to just point me in the direction of some references if the answer is tedious to explain.
Thanks!
FOLLOW UP:
I found an Apple example that did very nearly what I wanted to do. I made a lot of adjustments to it, but I'm banging my head against a wall trying to get the images to cycle. Here is what I think is the offending code, but I'm not sure what the solution is, as the ScrollView is functional, it just doesn't reset the center to the current view. Any ideas?
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
I'd just use a UIScrollView. Set the contentWidth to be 3 times the width/height of the view (for 3 pages) and set the contentOffset to be the center 'page' (view.bounds.size.width or view.bounds.size.height depending on whether you're scrolling horizontally/vertically respectively) . You'll need to setup a delegate for the UIScrollView (probably the view controller) and implement - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView. This will be called when the scroll view has finished decelerating. Once it has finished decelerating, reset the contentOffset back to the center view. This should give the impression of an infinite scroll. You can also set a counter to increment in the scrollViewDidEndDecelerating method to increment the counter or initiate the vibration.
You shouldn't need to keep repositioning the images. Just set the images once in the scrollView:
//Horizontal arrangement
UIImage *image = [UIImage imageNamed:#"nameOfImage.png"];
UIImageView *imageView1 = [[UIImageView alloc] initWithImage:image];
UIImageView *imageView2 = [[UIImageView alloc] initWithImage:image];
UIImageView *imageView3 = [[UIImageView alloc] initWithImage:image];
NSArray *imageViews = [NSArray arrayWithObjects:imageView1, imageView2, imageView3];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
[self.view addSubview: scrollView]; //This code assumes it's in a UIViewController
CGRect cRect = scrollView.bounds;
UIImageView *cView;
for (int i = 0; i < imageViews.count; i++){
cView = [imageViews objectAtIndex:i];
cView.frame = cRect;
[scrollView addSubview:cView];
cRect.origin.x += cRect.size.width;
}
scrollView.contentSize = CGSizeMake(cRect.origin.x, scrollView.bounds.size.height);
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0); //should be the center page in a 3 page setup
So the images are setup, you don't need to mess with them anymore. Just reset the contentOffset when the scroll views stops (note: you need to make sure you're the delegate of the scroll view or you'll not receive the message when the scroll view stops):
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
}
Please forgive any typos. I wrote it out by hand.
Look on cocoacontrols.com for a custom photo album view. As for the vibration, this code snippet vibrates the phone (make sure you link to and #import <AudioToolbox/AudioToolbox.h>):
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Been searching for this for quite a while, and I still haven't found a way to do it.
I'd like to reproduce the section headers of the iPhone's Spotlight into a UITableView.
"Regular" table view headers stay visible at the top of a section when you scroll, as we all know. But there is one kind of header that I've never seen elsewhere than in the Spotlight page of Springboard: there, the headers span the whole height of the section and are not stuck on the top of the section, but on the left side.
How the heck is that achieved?
Good question. I made a little experiment. It almost looks like the view from spotlight. But it's lacking one import feature. The lower "image" doesn't push the upper image to the top if they collide.
I doubt that there is a built in solution without the use of private frameworks.
I achieved this:
As you can see the two header images at the top overlap. They don't push each other like normal headers to. And I had to deactivate the cell separators. If I would use them they would appear at the whole cell. So you have to draw them yourself. Not a big deal.
But I have no idea how I could fix the overlapping.
Here is the code that made this happen:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 1;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 44)];
contentView.backgroundColor = [UIColor lightGrayColor];
UIImageView *imageView = [[[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 34, 34)] autorelease];
imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"%d", section]];;
[contentView addSubview:imageView];
return [contentView autorelease];
}
Okay I have done something similar to what the music app and spotlight search does.
I have not subclassed UITableView, I have just tracked the sections through it's scrollViewDidScroll method, and added the header views to the left of the tableView (so you will have to put the tableview to the right in your viewController's view, which means you can't use UITableViewController).
this method should be called in the scrollViewDidScroll, ViewDidLoad, and in didRotateFromInterfaceOrientation: (if you support rotation)
keep in mind that you will have to make space in the left equal to the size of the headers in any interface orientation that you support.
-(void)updateHeadersLocation
{
for (int sectionNumber = 0; sectionNumber != [self numberOfSectionsInTableView:self.tableView]; sectionNumber++)
{
// get the rect of the section from the tableview, and convert it to it's superview's coordinates
CGRect rect = [self.tableView convertRect:[self.tableView rectForSection:sectionNumber] toView:[self.tableView superview]];
// get the intersection between the section's rect and the view's rect, this will help in knowing what portion of the section is showing
CGRect intersection = CGRectIntersection(rect, self.tableView.frame);
CGRect viewFrame = CGRectZero; // we will start off with zero
viewFrame.size = [self headerSize]; // let's set the size
viewFrame.origin.x = [self headerXOrigin];
/*
three cases:
1. the section's origin is still showing -> header view will follow the origin
2. the section's origin isn't showing but some part of the section still shows -> header view will stick to the top
3. the part of the section that's showing is not sufficient for the view's height -> will move the header view up
*/
if (rect.origin.y >= self.tableView.frame.origin.y)
{
// case 1
viewFrame.origin.y = rect.origin.y;
}
else
{
if (intersection.size.height >= viewFrame.size.height)
{
// case 2
viewFrame.origin.y = self.tableView.frame.origin.y;
}
else
{
// case 3
viewFrame.origin.y = self.tableView.frame.origin.y + intersection.size.height - viewFrame.size.height;
}
}
UIView* view = [self.headerViewsDictionary objectForKey:[NSString stringWithFormat:#"%i", sectionNumber]];
// check if the header view is needed
if (intersection.size.height == 0)
{
// not needed, remove it
if (view)
{
[view removeFromSuperview];
[self.headerViewsDictionary removeObjectForKey:[NSString stringWithFormat:#"%i", sectionNumber]];
view = nil;
}
}
else if(!view)
{
// needed, but not available, create it and add it as a subview
view = [self headerViewForSection:sectionNumber];
if (!self.headerViewsDictionary && view)
self.headerViewsDictionary = [NSMutableDictionary dictionary];
if (view)
{
[self.headerViewsDictionary setValue:view forKey:[NSString stringWithFormat:#"%i", sectionNumber]];
[self.view addSubview:view];
}
}
[view setFrame:viewFrame];
}
}
also we need to declare a property that would keep the views that are visible:
#property (nonatomic, strong) NSMutableDictionary* headerViewsDictionary;
these methods return the size and X axis offset of the header views:
-(CGSize)headerSize
{
return CGSizeMake(44.0f, 44.0f);
}
-(CGFloat)headerXOrigin
{
return 10.0f;
}
I have Built the code so that any header view that's not needed gets removed, so we need a method that would return the view whenever needed:
-(UIView*)headerViewForSection:(NSInteger)index
{
UIImageView* view = [[UIImageView alloc] init];
if (index % 2)
{
[view setImage:[UIImage imageNamed:#"call"]];
}
else
{
[view setImage:[UIImage imageNamed:#"mail"]];
}
return view;
}
here's how it will look :
How it will look in lanscape, I have used contraints to give 44px in the left of the tableView
hope this helps :).
Good news: See answer of How to achieve an advanced table view header
result http://i.minus.com/jyea3I5qbUdoQ.png