I have built an iPhone app with a page to show the contents of a .txt file in UIScrollView. For some reason my plain txt file causes the Scrollview to allow it to pan slightly to the left and right, I want it to be solid up down scrolling only.
Really need help with this one..
Thanks
#import "ITFAQController.h"
#import "FTCoreTextView.h"
#implementation ITFAQController
- (NSString *)textForView {
NSString *path = [[NSBundle mainBundle] pathForResource:#"faq" ofType:#"txt"];
NSError *error;
return [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
}
/*- (id)init
{
self = [super init];
if (self) {
// Custom initialization
[self showLogoInNavBar:YES];
}
return self;
}
*/
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
[self showLogoInNavBar:YES];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 330, (self.view.bounds.size.height - 90))];
[self.view addSubview:scrollView];
FTCoreTextView *ctView = [[FTCoreTextView alloc] initWithFrame:CGRectMake(10, 0, 300, scrollView.bounds.size.height)];
[ctView setText:[self textForView]];
FTCoreTextStyle *defaultStyle = [FTCoreTextStyle styleWithName:FTCoreTextTagDefault];
[defaultStyle setFont:kITDescriptionFont];
[defaultStyle setTextAlignment:FTCoreTextAlignementJustified];
[defaultStyle setParagraphInset:UIEdgeInsetsMake(5, 10, 0, 0)];
[ctView addStyle:defaultStyle];
FTCoreTextStyle *title = [FTCoreTextStyle styleWithName:#"title"];
[title setFont:kITTitleFont];
[title setColor:kITCellFontColor];
[title setParagraphInset:UIEdgeInsetsMake(10, 0, 5, 0)];
[ctView addStyle:title];
FTCoreTextStyle *bold = [FTCoreTextStyle styleWithName:#"bold"];
[bold setFont:[UIFont boldSystemFontOfSize:14]];
[ctView addStyle:bold];
FTCoreTextStyle *link = [FTCoreTextStyle styleWithName:FTCoreTextTagLink];
[link setColor:[UIColor blueColor]];
[ctView addStyle:link];
FTCoreTextStyle *bullets = [FTCoreTextStyle styleWithName:FTCoreTextTagBullet];
[bullets setBulletColor:kITCellFontColor];
[bullets setFont:kITItalicFont];
[bullets setParagraphInset:UIEdgeInsetsMake(0, 10, 0, 0)];
[ctView addStyle:bullets];
[ctView fitToSuggestedHeight];
[scrollView addSubview:ctView];
[scrollView setContentSize:[ctView suggestedSizeConstrainedToSize:CGSizeMake(scrollView.bounds.size.width, CGFLOAT_MAX)]];
//[ctView fitToSuggestedHeight];
//[ctView sizeToFit];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
CGRectMake(0, 0, 330, (self.view.bounds.size.height - 90))];
Replace 330 with 320. That should do the trick.
Edit: As written in the comments you should prefer self.view.bounds.size.width
The problem likely has to do with this line:
[scrollView setContentSize:[ctView suggestedSizeConstrainedToSize:CGSizeMake(scrollView.bounds.size.width, CGFLOAT_MAX)]];
I don't know what that method does, but it's probably giving you a contentSize with width > 320. Adding the following lines after that would fix it, I think:
if (scrollView.contentSize.width > self.view.bounds.size.width)
[scrollView setContentSize:CGSizeMake(self.view.bounds.size.width,scrollView.contentSize.height)];
Related
I have a view with 3 ratings bars on it.
How do I tell them apart in the code? Right now if I change the top one it sees it fine but if I then change either or the other two it cannot separate them from one another.
The code is from git https://github.com/dyang/DYRateView
- (void)changedToNewRate:(NSNumber *)rate {
NSString *rating = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
NSLog(#"rating: %#",rating);
}
This is where is sees the changing.
And this is the .m file
#import "Survey.h"
#implementation Survey
#synthesize btnSubmit;
- (void)setUpEditableRateView {
DYRateView *rateService = [[DYRateView alloc] initWithFrame:CGRectMake(0, 55, self.view.bounds.size.width, 40) fullStar:[UIImage imageNamed:#"StarFullLarge#2x.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge#2x.png"]];
rateService.padding = 20;
rateService.alignment = RateViewAlignmentCenter;
rateService.editable = YES;
rateService.delegate =self;
[scroller addSubview:rateService];
[rateService release];
DYRateView *rateFood = [[DYRateView alloc] initWithFrame:CGRectMake(0, 130, self.view.bounds.size.width, 40) fullStar:[UIImage imageNamed:#"StarFullLarge#2x.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge#2x.png"]];
rateFood.padding = 20;
rateFood.alignment = RateViewAlignmentCenter;
rateFood.editable = YES;
rateFood.delegate = self;
[scroller addSubview:rateFood];
[rateFood release];
DYRateView *rateCleanliness = [[DYRateView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 40) fullStar:[UIImage imageNamed:#"StarFullLarge#2x.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge#2x.png"]];
rateCleanliness.padding = 20;
rateCleanliness.alignment = RateViewAlignmentCenter;
rateCleanliness.editable = YES;
rateCleanliness.delegate = self;
[scroller addSubview:rateCleanliness];
[rateCleanliness release];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
- (void)changedToNewRate:(NSNumber *)rate {
NSString *rating = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
NSLog(#"rating: %#",rating);
}
- (IBAction)btnSubmit:(id)sender{
}
-(IBAction)mainMenu{
[self dismissModalViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[scroller setScrollEnabled:YES];
[scroller setContentSize:CGSizeMake(320, 600)];
scroller.BackgroundColor = [UIColor clearColor];
[self setUpEditableRateView];
[btnSubmit useGreenConfirmStyle];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
UPDATE
ok with the new code I added an if statement
- (void)rateView:(DYRateView *)rateView changedToNewRate:(NSNumber *)rate {
NSString *barName = [NSString stringWithFormat:#"%#", rateView];
if (barName == #"rateView1") {
NSString *bar1 = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
NSLog(#"bar 1: %#",bar1);
}else if(barName == #"rateView2"){
NSString *bar2 = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
NSLog(#"bar 2: %#",bar2);
}else{
NSLog(#"NO BAR: %#",barName);
}
self.rateLabel.text = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
}
It works however Instead of getting back "rateView1" or 2 or 3. I get back
NO BAR: <DYRateView: 0x78229b0; frame = (0 40; 320 20); opaque = NO; layer =
<CALayer:0x7824900>>
Which is correct in nature but I was hoping for the name of the rateView such as "rateView1"
SOLUTION:
in .h file #property your 2 or 3 bars
#property(nonatomic, retain) DYRateView *rateView1,*rateView2;
in .m #synthesize them
#synthesize rateView1;
#synthesize rateView2;
then
(void)setUpEditableRateView {
rateView1 = [[DYRateView alloc] initWithFrame:CGRectMake(0, 40, self.view.bounds.size.width, 20) fullStar:[UIImage imageNamed:#"StarFullLarge.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge.png"]];
rateView1.padding = 20;
rateView1.alignment = RateViewAlignmentCenter;
rateView1.editable = YES;
rateView1.delegate = self;
[self.view addSubview:rateView1];
[rateView1 release];
rateView2 = [[DYRateView alloc] initWithFrame:CGRectMake(0, 100, self.view.bounds.size.width, 20) fullStar:[UIImage imageNamed:#"StarFullLarge.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge.png"]];
rateView2.padding = 20;
rateView2.alignment = RateViewAlignmentCenter;
rateView2.editable = YES;
rateView2.delegate = self;
[self.view addSubview:rateView2];
[rateView2 release];
// Set up a label view to display rate
self.rateLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 80, self.view.bounds.size.width, 20)] autorelease];
self.rateLabel.textAlignment = UITextAlignmentCenter;
self.rateLabel.text = #"Tap above to rate";
[self.view addSubview:self.rateLabel];
}
Then Finally
- (void)rateView:(DYRateView *)rateView changedToNewRate:(NSNumber *)rate {
if (rateView == rateView1) {
NSString *bar1 = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
NSLog(#"bar 1: %#",bar1);
}else if(rateView == rateView2){
NSString *bar2 = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
NSLog(#"bar 2: %#",bar2);
}else{
NSLog(#"NO BAR: %#",rateView);
}
self.rateLabel.text = [NSString stringWithFormat:#"Rate: %d", rate.intValue];
}
Thanks for using DYRateView!
The current version of DYRateView doesn't support listening to multiple instances all at the same time, but that doesn't mean that we can't do that. :)
If you don't mind updating the source code, you can find a method named notifyDelegate in DYRateView.m, and change [self.delegate performSelector:#selector(changedToNewRate:) withObject:[NSNumber numberWithFloat:self.rate]] to something like [self.delegate performSelector:#selector(rateView:changedToNewRate:) withObject:self withObject:[NSNumber numberWithFloat:self.rate]]. In this way you are able to pass the rateView itself as a parameter to its listener.
I haven't tried the above code yet as I don't have access to my Mac at this point, but I think this should give you an idea regarding how to achieve your goal.
I just set the tag for each of my rateviews to tell them apart, so in your example, I add a tag to each one:
#define serviceTag 1
#define foodTag 2
#define cleanlinessTag 3
- (void)setUpEditableRateView {
DYRateView *rateService = [[DYRateView alloc] initWithFrame:CGRectMake(0, 55, self.view.bounds.size.width, 40) fullStar:[UIImage imageNamed:#"StarFullLarge#2x.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge#2x.png"]];
rateService.padding = 20;
rateService.alignment = RateViewAlignmentCenter;
rateService.editable = YES;
rateService.tag = serviceTag;
rateService.delegate =self;
[scroller addSubview:rateService];
[rateService release];
DYRateView *rateFood = [[DYRateView alloc] initWithFrame:CGRectMake(0, 130, self.view.bounds.size.width, 40) fullStar:[UIImage imageNamed:#"StarFullLarge#2x.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge#2x.png"]];
rateFood.padding = 20;
rateFood.alignment = RateViewAlignmentCenter;
rateFood.editable = YES;
rateFood.tag = foodTag;
rateFood.delegate = self;
[scroller addSubview:rateFood];
[rateFood release];
DYRateView *rateCleanliness = [[DYRateView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 40) fullStar:[UIImage imageNamed:#"StarFullLarge#2x.png"] emptyStar:[UIImage imageNamed:#"StarEmptyLarge#2x.png"]];
rateCleanliness.padding = 20;
rateCleanliness.alignment = RateViewAlignmentCenter;
rateCleanliness.editable = YES;
rateCleanliness.delegate = self;
rateCleanliness.tag = cleanlinessTag;
[scroller addSubview:rateCleanliness];
[rateCleanliness release];
}
Then, in the delegate method, you can just check the tag:
- (void)rateView:(DYRateView *)rateView changedToNewRate:(NSNumber *)rate {
switch (rateView.tag) {
case foodTag:
// Do something for food
break;
case serviceTag:
// Do something for service
break;
case cleanlinessTag:
// Do something for cleanliness
break;
default:
break;
}
}
I want to add infinite scrolling images and there is no end for images scrolling:
const CGFloat kScrollObjHeight = 200.0;
const CGFloat kScrollObjWidth = 320.0;
const NSUInteger kNumImages = 17;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollview1 subviews];
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);
}
}
[scrollview1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollview1 bounds].size.height)];
}
-(void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
[scrollview1 setBackgroundColor:[UIColor blackColor]];
[scrollview1 setCanCancelContentTouches:NO];
scrollview1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollview1.clipsToBounds = YES;
scrollview1.scrollEnabled = YES;
scrollview1.pagingEnabled = YES;
for(int i=0;i< kNumImages;i++)
{
NSString *imgName=[[NSString alloc] initWithFormat:#"head%d.png",i];
UIImage *img=[UIImage imageNamed:imgName];
UIImageView *imageView=[[UIImageView alloc] initWithImage:img];
[imageView setFrame:CGRectMake(i* kScrollObjWidth, 0, kScrollObjWidth,kScrollObjHeight)];
[scrollview1 addSubview:imageView];
[imageView release];
[imgName release];
}
scrollview1.contentSize= CGSizeMake(kScrollObjWidth* kNumImages, kScrollObjHeight);
[self layoutScrollImages];
[super viewDidLoad];
}
Just make a simple new project with .h file as
#import <UIKit/UIKit.h>
#interface scrollableImageViewController : UIViewController {
IBOutlet UIScrollView *sview;
}
#end
and the .m file with this method
- (void)viewDidLoad {
[super viewDidLoad];
for(int i=0;i<10;i++)
{
NSString *name=[[NSString alloc] initWithFormat:#"images%d.png",i];
NSLog(#"%#",name);
[name release];
UIImage *img=[UIImage imageNamed:#"img.png"];
UIImageView *imageView=[[UIImageView alloc] initWithImage:img];
[imageView setFrame:CGRectMake(i*57, 0, 57, 57)];
[sview addSubview:imageView];
[imageView release];
}
sview.contentSize= CGSizeMake(57*10, 57);
}
and check the result
You can check out Apples sample code PhotoScroller.
It's the code they introduced at WWDC 11
in Session 104 - Advanced ScrollView Techniques. You can watch this video (and the corresponding PDF) for free if you are a registered Apple developer.
Hi in the main WiewController in the viewDidLoad i set up a
UIGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(processTap)];
and then i a for loop i create UIViews and add them to a scroll view, that is then added to the main view.
UIView *newsContainer = [[UIView alloc] initWithFrame:CGRectMake(160 * countnews, 30, 156, 126)];
newsContainer.tag = countnews;
newsContainer.userInteractionEnabled = YES;
[newsContainer addGestureRecognizer:recognizer];
[tempScroll addSubview:newsContainer];
then i have a function
- (void)processTap:(UITapGestureRecognizer *)recognizer {
UIView *view = recognizer.view;
NSLog(#"HELLO, %d", view.tag);
}
Which never gets called, any suggestions? your help would be greatly appreciated. Thanks in advance.
here is the entire .m
#import "iPadMainViewController.h"
#import "GradeintView.h"
#import <QuartzCore/CALayer.h>
#import "Category.h"
#import "News.h"
#import "LazyImageView.h"
#import "TouchView.h"
#interface iPadMainViewController ()
#end
#implementation iPadMainViewController
#synthesize detailsView = _detailsView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(processTap:)];
[recognizer setDelegate:self];
GradeintView *MainTitle = [[GradeintView alloc] initWithFrame:CGRectMake(0, 0, 1024, 50)];
GradeintView *MainSubTitle = [[GradeintView alloc] initWithFrame:CGRectMake(0, 50, 1024, 30)];
NSMutableArray *categoriesCollection = [[Category alloc] allCategoriesFromFeedAtUrl:#"http://geonews.ge/xml/category.php"];
UIScrollView *categories = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 512, 768)];
_detailsView = [[UIWebView alloc] initWithFrame:CGRectMake(500, 0, 512, 768)];
[_detailsView addGestureRecognizer:recognizer];
[categories setScrollEnabled:TRUE];
[categories setContentSize:CGSizeMake(500, categoriesCollection.count * 156)];
MainTitle.layer.masksToBounds = NO;
MainTitle.layer.shadowOffset = CGSizeMake(3, 3);
MainTitle.layer.shadowRadius = 5;
MainTitle.layer.shadowOpacity = 0.3;
[categories setBackgroundColor:[UIColor redColor]];
int counter = 0;
for (Category *cat in categoriesCollection)
{
UIView *categoryTitle = [[UIView alloc] initWithFrame:CGRectMake(0, 166 * counter
, 500, 20)];
UILabel *categoryLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 0, 200, 20)];
[categoryLabel setBackgroundColor:[UIColor clearColor]];
NSMutableArray *allCurrentNews = [[News alloc] allNewsFromCategory:cat.CategoryId];
categoryLabel.text = cat.Name;
categoryLabel.textColor = [UIColor whiteColor];
[categoryTitle addSubview:categoryLabel];
UIColor *myblack = [[UIColor alloc] initWithRed:0.14 green:0.14 blue:0.14 alpha:1];
UIColor *ligheterBlac = [[UIColor alloc] initWithRed:0.227 green:0.22 blue:0.22 alpha:1];
[categoryTitle setBackgroundColor:myblack];
UIScrollView *tempScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 166 * counter, 500, 166)];
UIColor *tempcolor = ligheterBlac;
tempScroll.layer.borderColor = [UIColor colorWithRed:0.34 green:0.34 blue:0.34 alpha:1].CGColor;
tempScroll.layer.borderWidth = 0.5f;
int countnews = 0;
for (News *news in allCurrentNews)
{
UIView *newsContainer = [[UIView alloc] initWithFrame:CGRectMake(160 * countnews, 30, 156, 126)];
newsContainer.tag = countnews;
[newsContainer addGestureRecognizer:recognizer];
//newsContainer.NewsId = news.NewsId;
LazyImageView *image = [[LazyImageView alloc] initWithURl:[NSURL URLWithString:news.Thumbnail]];
image.frame = CGRectMake(0, 0 , 156, 96);
UILabel *newsTitle = [[UILabel alloc] initWithFrame:CGRectMake(0, 96, 156, 30)];
newsTitle.backgroundColor = myblack;
newsTitle.numberOfLines = 2;
newsTitle.font = [UIFont systemFontOfSize:11];
newsTitle.text = news.Title;
newsTitle.textColor = [UIColor whiteColor];
newsTitle.textAlignment = UITextAlignmentCenter;
newsContainer.layer.borderColor = [UIColor colorWithRed:0.34 green:0.34 blue:0.34 alpha:1].CGColor;
newsContainer.layer.borderWidth = 0.5f;
[newsContainer addSubview:image];
[newsContainer addSubview:newsTitle];
countnews ++;
[tempScroll setContentSize:CGSizeMake(allCurrentNews.count * 156, 96)];
[tempScroll addSubview:newsContainer];
//[image release];
}
[tempScroll setBackgroundColor: tempcolor];
[categories addSubview:tempScroll];
[categories addSubview:categoryTitle];
[tempcolor release];
[tempScroll release];
counter ++;
}
self.detailsView.layer.masksToBounds = NO;
self.detailsView.layer.shadowOffset = CGSizeMake(-10, 5);
self.detailsView.layer.shadowRadius = 5;
self.detailsView.layer.shadowOpacity = 0.3;
[self.detailsView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.amazon.com"]]];
[self.view addSubview:categories];
[self.view addSubview:self.detailsView];
[self.view addSubview:MainSubTitle];
[self.view addSubview:MainTitle];
}
- (void)processTap:(UITapGestureRecognizer *)recognizer {
UIView *view = recognizer.view;
NSLog(#"HELLO, %d", view.tag);
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc {
[super dealloc];
}
- (void)loadDetailedContent:(NSString *)s
{
}
#end
Change
initWithTarget:self.view
to
initWithTarget:self
EDIT:
You also have forgotten colon:
initWithTarget:self action:#selector(processTap:)
EDIT2:
You have created _detailsView (with assigned UITapGestureRecognizer) but have not added it to any subview. How it will work?
I think the problem is that the scrollView, which contains your views, has its own internal gesture recognizer that is "taking away" touch events from your tap gesture recognizer. Try implementing the following gesture recognizer delegate method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Have you checked the Interaction setting?
Interaction shall be set to "User Interaction Enabled" in the Attributes inspector for the image.
Change #selector(processTap) to #selector(processTap:)
Because now you calling method that doesn't exist.
try this code
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(processTap)];
[newsContainer addGestureRecognizer::gestureRecognizer];
gestureRecognizer.cancelsTouchesInView = NO;
I assume the problem is, you might have missed to add <UIGestureRecognizerDelegate> in the header file.
You're adding a UIGestureRecognizer to a UIWebview, which is not recommended. UIWebview has its ownUIGestureRecognizer`s which are tricky to over-ride. See this SO question for more info.
you can first add your gestureRecognizer to self.view and check your method called or not... as well check this thread
Issue with a UITapGestureRecognizer
I have a imageView embedded in a scrollView. The imageView needs to be downloaded from the Internet (through flickr api), so I add a thread to handle this. But what am I supposed to do after I finished downloading the image? How can I reload my imageView?Here's my code.
In fact, it is working fine. but the imageView's size is (0, 0). How can I fix that?
- (void)viewDidLoad
{
[super viewDidLoad];
if (!self.myImage)
{
UIActivityIndicatorView* spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[spinner startAnimating];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:spinner];
dispatch_queue_t downloadQueue = dispatch_queue_create("flickr downloader (photo)", NULL);
dispatch_async(downloadQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:[FlickrFetcher urlForPhoto:self.photo format:FlickrPhotoFormatLarge]];
dispatch_async(dispatch_get_main_queue(), ^{
self.myImage = [UIImage imageWithData:data];
[self.imageView setImage:self.myImage];
[self viewDidLoad];
[self viewWillAppear:NO];
NSLog(#"imageViewSet!");
self.navigationItem.rightBarButtonItem = nil;
});
});
dispatch_release(downloadQueue);
}
else
{
NSString* imageTitle;
if ([[self.photo objectForKey:#"title"] length] > 0)
imageTitle = [self.photo objectForKey:#"title"];
else if ([[self.photo valueForKeyPath:#"description._content"] length] > 0)
imageTitle = [self.photo valueForKeyPath:#"description._content"];
else imageTitle = #"Unknown";
[[self navigationItem] setTitle:imageTitle];
self.scrollView.delegate = self;
self.scrollView.contentSize = self.imageView.image.size;
}
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
double scale = self.imageView.bounds.size.width * 1.0 / self.myImage.size.width;
if (scale > self.imageView.bounds.size.height * 1.0 / self.myImage.size.height)
scale = self.imageView.bounds.size.height * 1.0 / self.myImage.size.height;
NSLog(#"imgview%g, %g",self.imageView.bounds.size.width, self.imageView.bounds.size.height);
NSLog(#"img%g, %g",self.myImage.size.width, self.myImage.size.height);
self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
[self.scrollView setZoomScale:scale];
}
The usual way is to call:
[self.imageView setNeedsDisplay];
Edited to Add:
I just realized you said the image view is still (0,0). From the docs :
Setting the image property does not change the size of a UIImageView.
Call sizeToFit to adjust the size of the view to match the image.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
UIScrollView. Any thoughts on implementing “infinite” scroll/zoom?
I've got an UIScrollView and in it different images(about 30). I'd like to make it possible, when user reaches the last image to show the first one after it and so on. And I want to implement the same feature with the first image(to go to the last one).
I'd like to loop the images smoothly that user won't even notice that he is making another loop.
What is the best way to achieve this?
Thanks.
I've just done this. I have an array of images to add to the scrollview so I first of all add the last one to the scrollview, then run through the array to add all the images and then after that, add the first one from the array again.
Have a look through this code:
#import "MainViewController.h"
#import "MainView.h"
#define WIDTH_OF_SCROLL_PAGE 320
#define HEIGHT_OF_SCROLL_PAGE 352
#define WIDTH_OF_IMAGE 320
#define HEIGHT_OF_IMAGE 352
#define LEFT_EDGE_OFSET 0
#implementation MainViewController
#synthesize scrollView, slideImages;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
scrollView = [[UIScrollView alloc] init];
CGRect scrollFrame;
scrollFrame.origin.x = 0;
scrollFrame.origin.y = 0;
scrollFrame.size.width = WIDTH_OF_SCROLL_PAGE;
scrollFrame.size.height = HEIGHT_OF_SCROLL_PAGE;
scrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
scrollView.bounces = YES;
scrollView.pagingEnabled = YES;
scrollView.delegate = self;
scrollView.userInteractionEnabled = YES;
slideImages = [[NSMutableArray alloc] init];
[slideImages addObject:#"welcome-small.jpg"];
[slideImages addObject:#"football-small.jpg"];
[slideImages addObject:#"dancing-small.jpg"];
[slideImages addObject:#"celebration-small.jpg"];
//add the last image first
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[slideImages objectAtIndex:([slideImages count]-1)]]];
imageView.frame = CGRectMake(LEFT_EDGE_OFSET, 0, WIDTH_OF_IMAGE, HEIGHT_OF_IMAGE);
[scrollView addSubview:imageView];
[imageView release];
for (int i = 0;i<[slideImages count];i++) {
//loop this bit
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[slideImages objectAtIndex:i]]];
imageView.frame = CGRectMake((WIDTH_OF_IMAGE * i) + LEFT_EDGE_OFSET + 320, 0, WIDTH_OF_IMAGE, HEIGHT_OF_IMAGE);
[scrollView addSubview:imageView];
[imageView release];
//
}
//add the first image at the end
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[slideImages objectAtIndex:0]]];
imageView.frame = CGRectMake((WIDTH_OF_IMAGE * ([slideImages count] + 1)) + LEFT_EDGE_OFSET, 0, WIDTH_OF_IMAGE, HEIGHT_OF_IMAGE);
[scrollView addSubview:imageView];
[imageView release];
[scrollView setContentSize:CGSizeMake(WIDTH_OF_SCROLL_PAGE * ([slideImages count] + 2), HEIGHT_OF_IMAGE)];
[scrollView setContentOffset:CGPointMake(0, 0)];
[self.view addSubview:scrollView];
[self.scrollView scrollRectToVisible:CGRectMake(WIDTH_OF_IMAGE,0,WIDTH_OF_IMAGE,HEIGHT_OF_IMAGE) animated:NO];
[super viewDidLoad];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
int currentPage = floor((self.scrollView.contentOffset.x - self.scrollView.frame.size.width / ([slideImages count]+2)) / self.scrollView.frame.size.width) + 1;
if (currentPage==0) {
//go last but 1 page
[self.scrollView scrollRectToVisible:CGRectMake(WIDTH_OF_IMAGE * [slideImages count],0,WIDTH_OF_IMAGE,HEIGHT_OF_IMAGE) animated:NO];
} else if (currentPage==([slideImages count]+1)) {
[self.scrollView scrollRectToVisible:CGRectMake(WIDTH_OF_IMAGE,0,WIDTH_OF_IMAGE,HEIGHT_OF_IMAGE) animated:NO];
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[scrollView release];
[slideImages release];
[super dealloc];
}
#end
I then use scrollViewDidEndDecelerating to check where in the scroll the user is, and then jump them to the 2nd image or last but 1 image so they can scroll continuously... Sorry if I haven't explained it well - short of time! But this code is working fine for me on the device..
You can also have infinite scrolling without paging. Here is a great explanation at WWDC