HI i'm tring to create photogallery with two scrollviews
one for horizontal scrolling between images and second for zooming images.
scrolling between images works fine but i'm not able to zoom image into second scrollView.
mainScrollView named VcLicences
VcLicences.h
#import <UIKit/UIKit.h>
#interface VcLicences : UIViewController <UIScrollViewDelegate>{
IBOutlet UIScrollView* scrollView;
IBOutlet UIPageControl* pageControl;
BOOL pageControlIsChangingPage;
}
#property (nonatomic, retain) UIView *scrollView;
#property (nonatomic, retain) UIPageControl* pageControl;
/* for pageControl */
- (IBAction)changePage:(id)sender;
/* internal */
- (void)setupPage;
#end
VcLicences.m
#import "VcLicences.h"
#import "VcImageZoomView.h"
#implementation VcLicences
#synthesize scrollView;
#synthesize pageControl;
- (void)setupPage
{
scrollView.delegate = self;
[self.scrollView setBackgroundColor:[UIColor whiteColor]];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleBlack;
scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
scrollView.multipleTouchEnabled = NO;
NSUInteger nim = 0;
CGFloat cx = 0;
NSArray *licence = [NSArray arrayWithObjects:#"zl1.jpg", #"zl2.jpg", #"zl3.jpg", #"dph.jpg", #"or.jpg", nil];
for (nim=0; nim < [licence count]; nim++)
{
VcImageZoomView *imageZoom = [[VcImageZoomView alloc] initWithNibName:#"VcImageZoomView" bundle:nil];
[imageZoom.view setFrame:CGRectMake(cx, 0, 320, 332)];
[imageZoom setMyImage:[licence objectAtIndex:nim]];
[scrollView addSubview:imageZoom.view];
[imageZoom release];
cx += scrollView.frame.size.width;
}
self.pageControl.numberOfPages = nim;
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
}
#pragma mark UIScrollViewDelegate stuff
- (void)scrollViewDidScroll:(UIScrollView *)_scrollView
{
if (pageControlIsChangingPage)
{
return;
}
CGFloat pageWidth = _scrollView.frame.size.width;
int page = floor((_scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)_scrollView
{
pageControlIsChangingPage = NO;
}
- (IBAction)changePage:(id)sender
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlIsChangingPage = YES;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
self.navigationItem.title = #"CZECHMAT's licenses";
[self setupPage];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
//[scrollView release];
//[pageControl release];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (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.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
//return (interfaceOrientation == UIInterfaceOrientationPortrait);
return YES;
}
#end
second ScrollView for zooming images named VcImageZoomView
VcImageZoomView.h
#import <UIKit/UIKit.h>
#interface VcImageZoomView : UIViewController <UIScrollViewDelegate>{
IBOutlet UIScrollView *scroll;
UIImageView *image;
}
#property (nonatomic, retain) UIScrollView *scroll;
-(void)setMyImage:(NSString *) imageName;
#end
VcImageZoomView.m
#import "VcImageZoomView.h"
#implementation VcImageZoomView
#synthesize scroll;
-(void)setMyImage:(NSString *) imageName;
{
NSLog(#"%#", imageName);
image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
float scaleWidth = scroll.frame.size.width / image.frame.size.width;
float scaleHeight = scroll.frame.size.height / image.frame.size.height;
float scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
NSLog(#"%f", scale);
[scroll addSubview:image];
scroll.minimumZoomScale = scale;
scroll.maximumZoomScale = 1.0;
scroll.delegate = self;
[scroll setZoomScale:scroll.minimumZoomScale];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
[super dealloc];
}
- (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.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return image;
}
#end
thx for way
You really need to look at Apple's PhotoViewer sample and the WWDC'10 and '11 videos about ScrollViews: they are explaining in details (with this very example of a photoviewer scrolling and zooming) how to implement it:
How to recycle memory so that your memory footprint is drastically reduced (very important for fluidity)
How to handle both scrolling in one view and zooming in the other
If needed, how to do image tiling to optimize memory when zooming (only useful if you tiling is precomputed, so if you have images in your bundle anyway)
This is very interesting tutorials and videos and really worth reading/viewing.
https://github.com/doubleencore/KTPhotoBrowser
find above attached link get source code for photo gallery .....
Related
I am trying to update the UILabel of IBOutlet, however for some reason the content is not getting updated. Initially, the content is getting loaded from the model, which performs jsonResponse in async. However, I have set a delegate once the content is there to update the layout for which I am calling setNeedsDisplay.
Any help here would be appreciated.
Thanks.
The code below:
#interface pd ()
#property (nonatomic,retain) NSDictionary *pD;
#property (nonatomic, retain) pd_model *pdModel;
#end
#implementation pd
#synthesize pD = _pD, pdModel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil :(NSDictionary*)pD {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.productDetails = [[NSDictionary alloc] initWithDictionary:pD];
self.pdModel = [[ProductDetails_Model alloc] init:pD];
self.pdModel.delegate = self;
NSLog(#"%#",[self.pD description]);
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[scrollView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:scrollView];
scrollView.showsHorizontalScrollIndicator = YES;
scrollView.scrollEnabled = YES;
// Do any additional setup after loading the view from its nib.
productRecCarousel = [[iCarousel alloc] initWithFrame:CGRectMake(0.0f, scrollView.contentSize.height, 320.0f, 100.0)];
productRecCarousel.delegate = self;
[scrollView addSubview:productRecCarousel];
[self addProductDescription];
NSLog(#"%#",[self.pdModel responseCode]);
[soldBy setText:[self.pdModel responseCode]];
//[soldBy setText:#"1"];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark
#pragma mark CarouselDelegate methods
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel {
return 1;
}
- (NSUInteger)numberOfPlaceholdersInCarousel:(iCarousel *)carousel {
return 1;
}
- (UIView*)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view {
return [[UIView alloc] init];
}
- (CGFloat)carouselItemWidth:(iCarousel *)carousel {
//usually this should be slightly wider than the item views
return 150;
}
- (CATransform3D)carousel:(iCarousel *)_carousel transformForItemView:(UIView *)view withOffset:(CGFloat)offset {
//implement 'flip3D' style carousel
//set opacity based on distance from camera
view.alpha = 1.0 - fminf(fmaxf(offset, 0.0), 1.0);
//do 3d transform
CATransform3D transform = CATransform3DIdentity;
transform.m34 = _carousel.perspective;
transform = CATransform3DRotate(transform, M_PI / 8.0, 0, 1.0, 0);
return CATransform3DTranslate(transform, 0.0, 0.0, offset * _carousel.itemWidth);
}
- (void)addProductDescription {
NSLog(#"%f",addProductDetails.frame.size.height);
addProductDetails.frame = CGRectMake(0.0f, productRecCarousel.frame.size.height, addProductDetails.frame.size.width, addProductDetails.frame.size.height);
[scrollView addSubview:addProductDetails];
}
- (void)updateTheLayout {
//[self.view setNeedsDisplay];
//This is where I get the delegate called once the model is being updated. I tried scrollView and self.view setNeedsDisplay and setNeedsLayout but the IBoutlet never gets updated which is in "ViewDidLoad as assigned as" : [soldBy setText:[self.pdModel responseCode]];
}
Thanks.
so you just have to call [soldBy setText:[self.pdModel responseCode]]; from updateTheLayout and not from viewDidLoad because it is not ready yet. And please make sure to update the UI elements from the main thread.
You have to call [soldBy setText:[self.pdModel responseCode]]; in your callback, not in the viewDidLoad method.
I am trying to make practice app where i can scroll images with page control. I am able to scroll images and able to include the page control. But the problem i face is i am not able to interlink the two. Meaning to say when I scroll the images, the page control is not affected and when i change the page control, the scrolling of the images is unaffected.
I have referred to this: http://www.iosdevnotes.com/2011/03/uiscrollview-paging/ for the scrolling with page control.
Viewcontroller.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIScrollViewDelegate>{
UIScrollView *scrollView;
UIPageControl *pageControl;
BOOL pageControlBeingUsed;
}
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
#property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
- (IBAction)changePage;
#end
Viewcontroller.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize scrollView,pageControl;
- (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;
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
pageControlBeingUsed = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
pageControlBeingUsed = NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *images = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"1.jpeg"],[UIImage imageNamed:#"2.jpeg"],[UIImage imageNamed:#"3.jpeg" ], nil];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * images.count, self.scrollView.frame.size.height);
for (int i = 0; i < images.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView* imgView = [[UIImageView alloc] init];
imgView.image = [images objectAtIndex:i];
imgView.frame = frame;
[scrollView addSubview:imgView];
}
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = images.count;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.scrollView = nil;
self.pageControl = nil;
}
- (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;
}
#end
Need some guidance on this... Thanks..
I learned page control and scrollView from this tutorial, its very clearly written, hope it helps you http://www.raywenderlich.com/10518/how-to-use-uiscrollview-to-scroll-and-zoom-content
Check whether you have set the delegate of the scroll view to the ViewController
And you have just set the pageControlBeingUsed to YES or NO and you have not used it anywhere in the ViewController
Is there something that I need to remember when using the windows-based template? Because I'm unclear as to why the tabs are showing up but nothing in the views are showing up.
Could you help? Because I've been searching through previous questions for a few hours now and I still haven't found anything to clear this up.
AnotherMadeUpAppDelegate.h
#import <UIKit/UIKit.h>
#import "AnotherMadeUpViewController.h"
#interface AnotherMadeUpAppDelegate : NSObject <UIApplicationDelegate> {
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
AnotherMadeUpAppDelegate.m
#import "AnotherMadeUpAppDelegate.h"
#implementation AnotherMadeUpAppDelegate
#synthesize window=_window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UIViewController *vc1 = [[UIViewController alloc] init];
UIViewController *vc2 = [[UIViewController alloc] init];
AnotherMadeUpViewController *vc3 = [[AnotherMadeUpViewController alloc] init];
UITabBarController *tbc = [[UITabBarController alloc] init];
tbc.viewControllers = [NSArray arrayWithObjects:vc1, vc2, vc3, nil];
[vc1 release];
[vc2 release];
[vc3 release];
[self.window addSubview:tbc.view];
[self.window makeKeyAndVisible];
return YES;
}
...
#end
AnotherMadeUpViewController.h
#import <UIKit/UIKit.h>
#interface AnotherMadeUpViewController : UIViewController<UIScrollViewDelegate>
{
IBOutlet UIPageControl *pageControl;
IBOutlet UIScrollView *scroller;
IBOutlet UILabel *label;
}
#property (nonatomic,retain)IBOutlet UIPageControl *pageControl;
#property (nonatomic,retain)IBOutlet UIScrollView *scroller;
#property (nonatomic,retain)IBOutlet UILabel *label;
-(IBAction)clickPageControl:(id)sender;
#end
AnotherMadeUpViewController.m
#import "AnotherMadeUpViewController.h"
#implementation AnotherMadeUpViewController
#synthesize pageControl,scroller,label;
-(IBAction)clickPageControl:(id)sender
{
int page=pageControl.currentPage;
CGRect frame=scroller.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scroller scrollRectToVisible:frame animated:YES];
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
int page = scrollView.contentOffset.x/scrollView.frame.size.width;
pageControl.currentPage=page;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
[label release];
}
- (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.pagingEnabled=YES;
CGFloat labelOriginX = label.frame.origin.x;
CGFloat labelOriginY = label.frame.origin.y;
CGFloat scrollWidth = 0;
int pageNumber = 0;
for (int i=0; i<9; i++)
{
CGRect rect = label.frame;
rect.size.height = label.frame.size.height;
rect.size.width = label.frame.size.width;
rect.origin.x = labelOriginX + scrollWidth;
rect.origin.y = labelOriginY;
label.frame = rect;
label.text = [NSString stringWithFormat:#"%d", pageNumber];
label.textColor = [UIColor redColor];
[scroller addSubview:label];
pageNumber++;
scrollWidth += scroller.frame.size.width;
}
scroller.delegate=self;
scroller.directionalLockEnabled=YES;
scroller.showsHorizontalScrollIndicator=NO;
scroller.showsVerticalScrollIndicator=NO;
pageControl.numberOfPages=9;
pageControl.currentPage=0;
scroller.contentSize=CGSizeMake(pageControl.numberOfPages*self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:scroller];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[label release];
self.label = nil;
// 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
Dissecting your viewDidLoad –
scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width,self.view.frame.size.height)];
You seem to be creating a new scroll view instance here but you have declared it as an outlet. If you don't have an outlet then remove the IBOutlet tag for scroller. If you do have one and want to use it then remove the above line. A shorter way of doing it would be,
scroller = [[UIScrollView alloc] initWithFrame:self.view.bounds];
Another thing is that you are creating 10 labels but assigning no frame. To show one of them each in different page,
int pageNumber = 0;
for (int i = 0; i < 10; i++)
{
UILabel *label = [[UILabel alloc] init];
[label sizeToFit];
label.center = CGPointMake (((2 * i + 1) * self.view.frame.size.width) / 2, self.view.frame.size.height / 2);
label.text = [NSString stringWithFormat:#"%d", pageNumber];
[scroller addSubview:label];
[label release];
pageNumber++;
}
and later set the contentSize to show 10 pages,
scroller.contentSize = CGSizeMake(10 * self.view.frame.size.width, self.view.frame.size.height);
The problem is with this line
AnotherMadeUpViewController *vc3 = [[AnotherMadeUpViewController alloc] init];
You need to change it to
AnotherMadeUpViewController *vc3 = [[AnotherMadeUpViewController alloc] initWithNibName:#"AnotherMadeUpViewController" bundle:nil];
Then your .xib will get loaded and your outlets will be connected.
And don't forget to connect your outlets to File's owner in IB.
I have this code, modified version of Apple's PageScrollView sample. Here the differnce is that m using ViewControllers instead of UIView.
MyClass.h
#interface MyClass : UIViewController {
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;
BOOL pageControlUsed;
}
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
#property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
#property (nonatomic, retain) NSMutableArray *viewControllers;
- (IBAction)changePage:(id)sender;
#end
MyClass.m
#import "MyClass.h"
#import "MyViewController.h"
#import "MyViewControllerZero.h"
#import "MyViewControllerOne.h"
#import "MyViewControllerTwo.h"
static NSUInteger kNumberOfPages = 3;
#interface MyClass (PrivateMethods)
- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;
#end
#implementation MyClass
#synthesize scrollView, pageControl, viewControllers;
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
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];
}
- (void)loadScrollViewWithPage:(int)page {
// if (page < 0) return;
// if (page >= kNumberOfPages) return;
if(page==0)
{
MyViewControllerZero *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null])
{ controller = [[MyViewControllerZero alloc] init];
[viewControllers replaceObjectAtIndex:page withObject:controller];
if (nil == controller.view.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
}
if(page==1)
{
MyViewControllerOne *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null])
{ controller = [[MyViewControllerOne alloc] init];
[viewControllers replaceObjectAtIndex:page withObject:controller];
if (nil == controller.view.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
}
if(page==2)
{
MyViewControllerTwo *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null])
{ controller = [[MyViewControllerTwo alloc] init];
[viewControllers replaceObjectAtIndex:page withObject:controller];
if (nil == controller.view.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
}
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (pageControlUsed) {
return;
}
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
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (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)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 {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[viewControllers release];
[scrollView release];
[pageControl release];
[super dealloc];
}
#end
The Above code works absolutely fine in the potrait mode. But when i change the orientation,the whole paging gets screwed up.. :((
please help me to resolve this problem..
Apple didn't design UIViewController to work at any point in a view hierarchy. The views that you're adding to your UIScrollView are managed by view controllers, but I think you'll find that the view controllers for those views don't receive rotation events.
You could try to manually forward all events from the scroll view's controller to the child view controllers, but I think you'll find that to be tedious and error prone. I'd suggest instead that you simply use a single view controller for the scroll view and its child views.
I have successfully integrated the three20 framework in my project,
and I have extended the TTPhotoViewController to add some further
functionality.
Now I need to add some subviews to the TTPhotoView loaded by the
TTPhotoViewController. In particular I would like to add that subviews
after every TTPhotoView as been loaded. These subviews represents
sensible area over the image so they should scale proportionally with
the image.
The user can tap a subview to get extra info about the image.
I don't know how to implement this behavior. Should I extend the
TTPhotoView and make sure that the TTPhotoViewController use this
extended version instead of its TTPhotoView?
Could someone point me to the right direction?
Thank you
Solved subclassing the TTPhotoView (TapDetectingPhotoView) and then adding all my subviews to that subclass.
The main problem was represented by the photo switching, because the TTPhotoViewController (in particular its inner TTScrollView) reuse the TTPhotoView during switching operation.
So for example if you add your subview to your TTPhotoView subclass and try to switch to the next photo, your subview will probably be here, because the TTPhotoView is reused.
To solve this problem I decided to add and remove all my subviews every time a photo switch occur (see TTPhotoViewController::didMoveToPhoto).
In this way I'm sure that every photoview has its subviews.
Here my implementation (only remarkable methods)
Hope these help!
PhotoViewController.h:
#import "TapDetectingPhotoView.h"
#interface PhotoGalleryController : TTPhotoViewController <TTScrollViewDelegate, TapDetectingPhotoViewDelegate> {
NSArray *images;
}
#property (nonatomic, retain) NSArray *images;
#end
PhotoViewController.m:
#import "PhotoGalleryController.h"
#implementation PhotoGalleryController
#synthesize images;
- (void)viewDidLoad { // fill self.images = ... }
- (TTPhotoView*)createPhotoView {
TapDetectingPhotoView *photoView = [[TapDetectingPhotoView alloc] init];
photoView.tappableAreaDelegate = self;
return [photoView autorelease];
}
#pragma mark -
#pragma mark TTPhotoViewController
- (void)didMoveToPhoto:(id<TTPhoto>)photo fromPhoto:(id<TTPhoto>)fromPhoto {
[super didMoveToPhoto:photo fromPhoto:fromPhoto];
TapDetectingPhotoView *previousPhotoView = (TapDetectingPhotoView *)[_scrollView pageAtIndex:fromPhoto.index];
TapDetectingPhotoView *currentPhotoView = (TapDetectingPhotoView *)[_scrollView pageAtIndex:photo.index];
// destroy the sensible areas from the previous photoview, because the photo could be reused by the TTPhotoViewController!
if (previousPhotoView)
previousPhotoView.sensibleAreas = nil;
// if sensible areas has not been already created, create new
if (currentPhotoView && currentPhotoView.sensibleAreas == nil) {
currentPhotoView.sensibleAreas = [[self.images objectAtIndex:photo.index] valueForKey:#"aMap"];
[self showSensibleAreas:YES animated:YES];
}
}
#pragma mark -
#pragma mark TappablePhotoViewDelegate
// show a detail view when a sensible area is tapped
- (void)tapDidOccurOnSensibleAreaWithId:(NSUInteger)ids {
NSLog(#"SENSIBLE AREA TAPPED ids:%d", ids);
// ..push new view controller...
}
TapDetectingPhotoView.h:
#import "SensibleAreaView.h"
#protocol TapDetectingPhotoViewDelegate;
#interface TapDetectingPhotoView : TTPhotoView <SensibleAreaViewDelegate> {
NSArray *sensibleAreas;
id <TapDetectingPhotoViewDelegate> tappableAreaDelegate;
}
#property (nonatomic, retain) NSArray *sensibleAreas;
#property (nonatomic, assign) id <TapDetectingPhotoViewDelegate> tappableAreaDelegate;
#end
#protocol TapDetectingPhotoViewDelegate <NSObject>
#required
- (void)tapDidOccurOnSensibleAreaWithId:(NSUInteger)ids;
#end
TapDetectingPhotoView.m:
#import "TapDetectingPhotoView.h"
#interface TapDetectingPhotoView (Private)
- (void)createSensibleAreas;
#end
#implementation TapDetectingPhotoView
#synthesize sensibleAreas, tappableAreaDelegate;
- (id)init {
return [self initWithSensibleAreas:nil];
}
- (id)initWithFrame:(CGRect)frame {
return [self initWithSensibleAreas:nil];
}
// designated initializer
- (id)initWithSensibleAreas:(NSArray *)areasList {
if (self = [super initWithFrame:CGRectZero]) {
self.sensibleAreas = areasList;
[self createSensibleAreas];
}
return self;
}
- (void)setSensibleAreas:(NSArray *)newSensibleAreas {
if (newSensibleAreas != self.sensibleAreas) {
// destroy previous sensible area and ensure that only sensible area's subviews are removed
for (UIView *subview in self.subviews)
if ([subview isMemberOfClass:[SensibleAreaView class]])
[subview removeFromSuperview];
[newSensibleAreas retain];
[sensibleAreas release];
sensibleAreas = newSensibleAreas;
[self createSensibleAreas];
}
}
- (void)createSensibleAreas {
SensibleAreaView *area;
NSNumber *areaID;
for (NSDictionary *sensibleArea in self.sensibleAreas) {
CGFloat x1 = [[sensibleArea objectForKey:#"nX1"] floatValue];
CGFloat y1 = [[sensibleArea objectForKey:#"nY1"] floatValue];
area = [[SensibleAreaView alloc] initWithFrame:
CGRectMake(
x1, y1,
[[sensibleArea objectForKey:#"nX2"] floatValue]-x1, [[sensibleArea objectForKey:#"nY2"] floatValue]-y1
)
];
areaID = [sensibleArea objectForKey:#"sId"];
area.ids = [areaID unsignedIntegerValue]; // sensible area internal ID
area.tag = [areaID integerValue];
area.delegate = self;
[self addSubview:area];
[area release];
}
}
// to make sure that if the zoom factor of the TTScrollView is > than 1.0 the subviews continue to respond to the tap events
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *result = nil;
for (UIView *child in self.subviews) {
CGPoint convertedPoint = [self convertPoint:point toView:child];
if ([child pointInside:convertedPoint withEvent:event]) {
result = child;
}
}
return result;
}
#pragma mark -
#pragma mark TapDetectingPhotoViewDelegate methods
- (void)tapDidOccur:(SensibleAreaView *)aView {
NSLog(#"tapDidOccur ids:%d tag:%d", aView.ids, aView.tag);
[tappableAreaDelegate tapDidOccurOnSensibleAreaWithId:aView.ids];
}
SensibleAreaView.h:
#protocol SensibleAreaViewDelegate;
#interface SensibleAreaView : UIView {
id <SensibleAreaViewDelegate> delegate;
NSUInteger ids;
UIButton *disclosureButton;
}
#property (nonatomic, assign) id <SensibleAreaViewDelegate> delegate;
#property (nonatomic, assign) NSUInteger ids;
#property (nonatomic, retain) UIButton *disclosureButton;
#end
#protocol SensibleAreaViewDelegate <NSObject>
#required
- (void)tapDidOccur:(SensibleAreaView *)aView;
#end
SensibleAreaView.m:
#import "SensibleAreaView.h"
#implementation SensibleAreaView
#synthesize delegate, ids, disclosureButton;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.userInteractionEnabled = YES;
UIColor *color = [[UIColor alloc] initWithWhite:0.4 alpha:1.0];
self.backgroundColor = color;
[color release];
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[button addTarget:self action:#selector(buttonTouched) forControlEvents:UIControlEventTouchUpInside];
CGRect buttonFrame = button.frame;
// set the button position over the right edge of the sensible area
buttonFrame.origin.x = frame.size.width - buttonFrame.size.width + 5.0f;
buttonFrame.origin.y = frame.size.height/2 - 10.0f;
button.frame = buttonFrame;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin |UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
self.disclosureButton = button;
[self addSubview:button];
// notification used to make sure that the button is properly scaled together with the photoview. I do not want the button looks bigger if the photoview is zoomed, I want to preserve its default dimensions
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(zoomFactorChanged:) name:#"zoomFactorChanged" object:nil];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if ([[touches anyObject] tapCount] == 1)
[delegate tapDidOccur:self];
}
- (void)buttonTouched {
[delegate tapDidOccur:self];
}
- (void)zoomFactorChanged:(NSNotification *)message {
NSDictionary *userInfo = [message userInfo];
CGFloat factor = [[userInfo valueForKey:#"zoomFactor"] floatValue];
BOOL withAnimation = [[userInfo valueForKey:#"useAnimation"] boolValue];
if (withAnimation) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.18];
}
disclosureButton.transform = CGAffineTransformMake(1/factor, 0.0, 0.0, 1/factor, 0.0, 0.0);
if (withAnimation)
[UIView commitAnimations];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"zoomFactorChanged" object:nil];
[disclosureButton release];
[super dealloc];
}
Some ideas:
Subclass TTPhotoView, then override createPhotoView in your TTPhotoViewController:
- (TTPhotoView*)createPhotoView {
return [[[MyPhotoView alloc] init] autorelease];
}
Try overriding a private method (yes, bad practice, but hey) setImage: in TTPhotoView subclass:
- (void)setImage:(UIImage*)image {
[super setImage:image]
// Add a subview with the frame of self.view, maybe?..
//
// Check for self.isLoaded (property of TTImageView
// which is subclassed by TTPhotoView) to check if
// the image is loaded
}
In general, look at the headers and implementations (for the private methods) of TTPhotoViewController and TTPhotoView. Set some breakpoints to figure out what does what :)
Interesting question. Facebook has a similar functionality with their tags. Their tags do not scale proportionally with the image. In fact, they do not even show the tags if you have zoomed. I don't know if this will help you, but I would look at how (if) three20 handles tags and then maybe try to extend that.