I am working on an application where i need to zoom a UIView on click of UITapGestureRecognizer and want to perform a IBAction while zooming and after zooming. Is this possible?. Please give me a small example of it.
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleDoubleTap:)];
tapGestureRecognizer.numberOfTapsRequired = 2;
[self.scrollContainer addGestureRecognizer:tapGestureRecognizer];
}
- (void)handleDoubleTap:(UIGestureRecognizer *)recognizer
{
if(isAlreadyZoomed)
{
CGPoint Pointview = [recognizer locationInView:recognizer.view];
CGFloat newZoomscal = 3.0;
CGSize scrollViewSize = self.scrollContainer.bounds.size;
CGFloat width = scrollViewSize.width/newZoomscal;
CGFloat height = scrollViewSize.height /newZoomscal;
CGFloat xPos = Pointview.x-(width/2.0);
CGFloat yPos = Pointview.y-(height/2.0);
CGRect rectTozoom = CGRectMake(xPos, yPos, width, height);
[self.scrollContainer zoomToRect:rectTozoom animated:YES];
[self.scrollContainer setZoomScale:3.0 animated:YES];
isAlreadyZoomed = NO;
}
else
{
[self.scrollContainer setZoomScale:1.0 animated:YES];
isAlreadyZoomed = YES;
}
}
IBAction are just regular methods that returns void and take 0 or 1 argument only.
You can call them in code as you would call any other king of methods.
UITapGestureRecognizer are design to call an IBAction method while triggered. You can set that from InterfaceBuilder or in code
for example the following code
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleTap:)];
tap.numberOfTapsRequired = 2;
[imageView addGestureRecognizer:[tap cop]];
will called this methods when the user doubleTap the imageView
- (void) handleTap:(UITapGestureRecognizer *)sender;
in this methods, you can pretty much do whatever you need:
managing your subviews,
calling other methods etc...
However, if you plan an zooming in and out, I would strongly recommand the usage of the UIScrollView class instead of the UIView class.
Cheers
hi i hope below would give u a idea.....
UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
tap2.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:tap2];
- (void) scrollViewDoubleTapped:(UITapGestureRecognizer *)sender
{
scrollZoomAdjust.zoomScale=2.0f;// set your required Zoom scale
// scrollZoomAdjust is the scroll view that contain the image within it
}
the above code was not tested
Related
I have a view controller with half table view (bottom, 320x289)and half map view (top, 320,289). How can I detect location of tap?
Currently my code for the tap looks like this - when tapping, it hides the navigation bar so that the map gets some extra real estate. However, because it's not detecting location of the tap, when I tap on the tableview, I'm not able to segue into my table view controller.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideShowNavigation)];
tap.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tap];
Ideally I would like to detect location of taps. If tapped at the top (if height <=289px), it hides navigation bar (or maybe even segue into a separate view controller where map is full screen). If tapped at the bottom (if height > 289px), then it pushes the segue into table view controller.
- (void) hideShowNavigation:(id)sender
{
[self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden];
[self hidesBottomBarWhenPushed];
}
Here's the whole code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.navigationBar.translucent = YES;
self.automaticallyAdjustsScrollViewInsets = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideShowNavigation:)];
tap.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tap];
}
- (void) hideShowNavigation:(id)sender
{
CGPoint = [sender locationInView:self.view];
CGFloat y = location.y;
if(y<=289){
[self.navigationController setNavigationBarHidden:!self.navigationController.navigationBarHidden];
[self hidesBottomBarWhenPushed];
}
}
In your selector:
CGPoint location = [sender locationInView:self.view];
CGFloat x = location.x;
CGFloat y = location.y;
In my TestApp, I created a class "Carousel" which should let me create a swipe menu with a UIPageControl in an easy way (by simply creating an instance of the class Carousel).
Carousel is a subclass of UIView
At init, it creates an UIView, containing UIScrollView, UIPageControl
I can add further UIViews to the scroll view
I don't know if this is the proper way to do it, but my example worked quite well in my TestApp. Swiping between pages works perfectly and the display of the current page in the UIPageControl is correct.
If there were not one single problem: The UIPageControl sometimes reacts to clicks/taps (I only tested in Simulator so far!), sometimes it doesn't. Let's say most of the time it doesn't. I couldn't find out yet when it does, for me it's just random...
As you can see below, I added
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
to my code. I thought this would do the proper handling of taps? But unfortunately, pageChange doesn't get always called (so the value of the UIPageControl doesn't change every time I click).
I would appreciate any input on this because I couldn't find any solution on this yet.
This is what I have so far:
Carousel.h
#import <UIKit/UIKit.h>
#interface Carousel : UIView {
UIScrollView *scrollView;
UIPageControl *pageControl;
BOOL pageControlBeingUsed;
}
- (void)addView:(UIView *)view;
- (void)setTotalPages:(NSUInteger)pages;
- (void)setCurrentPage:(NSUInteger)current;
- (void)createPageControlAt:(CGRect)cg;
- (void)createScrollViewAt:(CGRect)cg;
#end
Carousel.m
#import "Carousel.h"
#implementation Carousel
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Create a scroll view
scrollView = [[UIScrollView alloc] init];
[self addSubview:scrollView];
scrollView.delegate = (id) self;
// Init Page Control
pageControl = [[UIPageControl alloc] init];
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
[self addSubview:pageControl];
}
return self;
}
- (IBAction)pageChange:(id)sender {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:TRUE];
NSLog(#"%i", pageControl.currentPage);
}
- (void)addView:(UIView *)view {
[scrollView addSubview:view];
}
- (void)createPageControlAt:(CGRect)cg {
pageControl.frame = cg;
}
- (void)setTotalPages:(NSUInteger)pages {
pageControl.numberOfPages = pages;
}
- (void)setCurrentPage:(NSUInteger)current {
pageControl.currentPage = current;
}
- (void)createScrollViewAt:(CGRect)cg {
[scrollView setPagingEnabled:TRUE];
scrollView.frame = cg;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*pageControl.numberOfPages, scrollView.frame.size.height);
[scrollView setShowsHorizontalScrollIndicator:FALSE];
[scrollView setShowsVerticalScrollIndicator:FALSE];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float frac = scrollView.contentOffset.x / scrollView.frame.size.width;
NSUInteger page = lround(frac);
pageControl.currentPage = page;
}
#end
ViewController.m (somewhere in viewDidLoad)
Carousel *carousel = [[Carousel alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
for (int i=0; i<5; i++) {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i * 320, 0, 320, 420)];
UIColor *color;
if(i%3==0) color = [UIColor blueColor];
else if(i%3==1) color = [UIColor redColor];
else color = [UIColor purpleColor];
view.backgroundColor = color;
[carousel addView:view];
view = nil;
}
[carousel setTotalPages:5];
[carousel setCurrentPage:0];
[carousel createPageControlAt:CGRectMake(0,420,320,40)];
[carousel createScrollViewAt:CGRectMake(0,0,320,420)];
Your code is correct. Most likely the frame of your pageControl is pretty small, so theres not a lot of area to look for touch events. You would need to increase the size of the height of pageControl in order to make sure taps are recognized all of the time.
Currently I'm facing a problem, I would like to perform action when the UIImageView on my UITableViewCell had been tapped.
Question: How could I do it? Could any one show me the code, or any tutorial?
Thanks in advance!
This is actually easier than you would think. You just need to make sure that you enable user interaction on the imageView, and you can add a tap gesture to it. This should be done when the cell is instantiated to avoid having multiple tap gestures added to the same image view. For example:
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(myTapMethod:)];
[self.imageView addGestureRecognizer:tap];
[self.imageView setUserInteractionEnabled:YES];
}
return self;
}
- (void)myTapMethod:(UITapGestureRecognizer *)tapGesture
{
UIImageView *imageView = (UIImageView *)tapGesture.view;
NSLog(#"%#", imageView);
}
Try this
//within cellForRowAtIndexPath (where customer table cell with imageview is created and reused)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleImageTap:)];
tap.cancelsTouchesInView = YES;
tap.numberOfTapsRequired = 1;
[imageView addGestureRecognizer:tap];
// handle method
- (void) handleImageTap:(UIGestureRecognizer *)gestureRecognizer
{
RKLogDebug(#"imaged tab");
}
make sure u have....
imageView.userInteractionEnabled = YES;
you can use a customButton instead UIImageView
A tap gesture recogniser can be very memory hungry and can cause other things on the page to break. I would personally reconmend you create a custom table cell, insert a button into the custom cell frame and in the tableview code set the self.customtablecell.background.image to the image you want. This way you can assign the button an IBaction to make it push to whatever view you want.
Use ALActionBlocks to action in block
__weak ALViewController *wSelf = self;
imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithBlock:^(UITapGestureRecognizer *weakGR) {
NSLog(#"pan %#", NSStringFromCGPoint([weakGR locationInView:wSelf.view]));
}];
[self.imageView addGestureRecognizer:gr];
how to change the width of the UIPickerView in objective C, I am using the following code,
tempFiled = Data;
[tempFiled resignFirstResponder];
CGSize sizeOfPopover = CGSizeMake(200, 200);
CGPoint positionOfPopover = CGPointMake(32, 325);
[popOverControllerWithPicker presentPopoverFromRect:CGRectMake(positionOfPopover.x, positionOfPopover.y+10, 500, sizeOfPopover.height)
inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
But when i am trying to change the width in CGSize sizeOfPopover = CGSizeMake(200, 200); its not changing, i want to reduce the size of the picker.
I had this problem and solved it this way:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CGRect frame = bpsPicker.frame;
frame.size.width = 100; // width to be displayed on popover controller
bpsPicker.frame = frame;
}
Using ViewDidLoad() is too early to alter this value.
To be clear the viewWillAppear is in the UIViewController that is passed to the UIPopover (here called 'MyViewController.m').So,
self.myViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil] ;
self.myViewController.delegate = self;
self.myViewController.contentSizeForViewInPopover = CGSizeMake(320, 360); // or whatever
self.myViewControllerPopover = [[UIPopoverController alloc] initWithContentViewController:self.myViewController] ;
[self.myViewControllerPopover presentPopoverFromBarButtonItem:self.myToolBarButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
In my application, I would like to present the user with a full-screen photo viewer much like the one used in the Photos app. This is just for a single photo and as such should be quite simple. I just want the user to be able to view this one photo with the ability to zoom and pan.
I have most of it working. And, if I do not center my UIImageView, everything behaves perfectly. However, I really want the UIImageView to be centered on the screen when the image is sufficiently zoomed out. I do not want it stuck to the top-left corner of the scroll view.
Once I attempt to center this view, my vertical scrollable area appears to be greater than it should be. As such, once I zoom in a little, I am able to scroll about 100 pixels past the top of the image. What am I doing wrong?
#interface MyPhotoViewController : UIViewController <UIScrollViewDelegate>
{
UIImage* photo;
UIImageView *imageView;
}
- (id)initWithPhoto:(UIImage *)aPhoto;
#end
#implementation MyPhotoViewController
- (id)initWithPhoto:(UIImage *)aPhoto
{
if (self = [super init])
{
photo = [aPhoto retain];
// Some 3.0 SDK code here to ensure this view has a full-screen
// layout.
}
return self;
}
- (void)dealloc
{
[photo release];
[imageView release];
[super dealloc];
}
- (void)loadView
{
// Set the main view of this UIViewController to be a UIScrollView.
UIScrollView *scrollView = [[UIScrollView alloc] init];
[self setView:scrollView];
[scrollView release];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Initialize the scroll view.
CGSize photoSize = [photo size];
UIScrollView *scrollView = (UIScrollView *)[self view];
[scrollView setDelegate:self];
[scrollView setBackgroundColor:[UIColor blackColor]];
// Create the image view. We push the origin to (0, -44) to ensure
// that this view displays behind the navigation bar.
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, -44.0,
photoSize.width, photoSize.height)];
[imageView setImage:photo];
[scrollView addSubview:imageView];
// Configure zooming.
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
CGFloat widthRatio = screenSize.width / photoSize.width;
CGFloat heightRatio = screenSize.height / photoSize.height;
CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;
[scrollView setMaximumZoomScale:3.0];
[scrollView setMinimumZoomScale:initialZoom];
[scrollView setZoomScale:initialZoom];
[scrollView setBouncesZoom:YES];
[scrollView setContentSize:CGSizeMake(photoSize.width * initialZoom,
photoSize.height * initialZoom)];
// Center the photo. Again we push the center point up by 44 pixels
// to account for the translucent navigation bar.
CGPoint scrollCenter = [scrollView center];
[imageView setCenter:CGPointMake(scrollCenter.x,
scrollCenter.y - 44.0)];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[[self navigationController] navigationBar] setBarStyle:UIBarStyleBlackTranslucent];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[[self navigationController] navigationBar] setBarStyle:UIBarStyleDefault];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return imageView;
}
#end
This code should work on most versions of iOS (and has been tested to work on 3.1 upwards).
It's based on the Apple WWDC code for PhotoScroller.
Add the below to your subclass of UIScrollView, and replace tileContainerView with the view containing your image or tiles:
- (void)layoutSubviews {
[super layoutSubviews];
// center the image as it becomes smaller than the size of the screen
CGSize boundsSize = self.bounds.size;
CGRect frameToCenter = tileContainerView.frame;
// center horizontally
if (frameToCenter.size.width < boundsSize.width)
frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
else
frameToCenter.origin.x = 0;
// center vertically
if (frameToCenter.size.height < boundsSize.height)
frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
else
frameToCenter.origin.y = 0;
tileContainerView.frame = frameToCenter;
}
Have you checked out the UIViewAutoresizing options?
(from the documentation)
UIViewAutoresizing
Specifies how a view is automatically resized.
enum {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
typedef NSUInteger UIViewAutoresizing;
Are you using IB to add the scroll view? Change the autosizing options of the scrollview to the attached image.
I think the reason behind it is because the zoomScale applies to the whole contentSize, regardless of the actual size of the subview inside the scrollView (in your case it's an imageView). The contentSize height seems to be always equal or greater than the height of the scrollView frame, but never smaller. So when applying a zoom to it, the height of the contentSize gets multiplied by the zoomScale factor as well, that's why you're getting an extra 100-something pixels of vertical scroll.
You probably want to set the bounds of the scroll view = bounds of the image view, and then center the scroll view in its containing view. If you place a view inside a scroll view at an offset from the top, you will get that empty space above it.