I want users to be able to use pinch to zoom in my app which uses Storyboard and programmatically generated buttons and labels to produce a View within a Viewcontroller. In the View's Attribute inspector I have checked both User Interaction Enabled and Multiple Touch. But no pinch to zoom seems to work.
The code which creates the important part of the View is as follows.
- (void)viewDidLoad
{
[super viewDidLoad];
NSInteger xPipsOrigin = 0;
NSInteger xPipsStep = 22.0;
NSString* cards = #"AKQJT98765432";
NSInteger yPipsOrigin = 100;
if (UI_USER_INTERFACE_IDIOM()== UIUserInterfaceIdiomPhone){
xPipsOrigin = 0;
xPipsStep = 22.0;
xPipsStep = 34.0;
}
else{
xPipsOrigin = 100;
xPipsStep = 40.0;
}
NSInteger xPipsCurrent = xPipsOrigin;
self.countCards = 0;
self.cardList = [NSMutableArray arrayWithCapacity:0];
yPipsOrigin = 100;
xPipsCurrent = xPipsOrigin;
for( int x=0;x<[cards length]; x++ ){
[cards substringWithRange:NSMakeRange(x,1)];
UIButton *b= [UIButton buttonWithType:UIButtonTypeRoundedRect];
xPipsCurrent += xPipsStep;
[b setTitle:[cards substringWithRange:NSMakeRange(x,1)] forState:UIControlStateNormal];
[b setTitle:#" " forState:UIControlStateDisabled];
[b setFrame:CGRectMake(xPipsCurrent, yPipsOrigin, 20, 20)];
[b setEnabled:YES];
[b setUserInteractionEnabled:YES];
[self.view addSubview:b];
[b addTarget:self action:#selector(spadeButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
xPipsCurrent = xPipsOrigin + xPipsStep/2;
for( int x=0;x<[cards length]-1; x++ ){
xPipsCurrent += xPipsStep;
UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake( 0, 0, 20, 20)];
lab.text = #"\u2660";
lab.backgroundColor = [UIColor clearColor];
lab.center = CGPointMake(xPipsCurrent+10, yPipsOrigin+10);
[self.view addSubview:lab];
}
}
How can I enable Pinch to Zoom in this app?
If you want to enable pinch to zoom on a UIView you have to wrap it into a UIScrollView first
Whilst you can use User Interaction Enabled and try do it that way, it'll be easier to add a UIGestureRecogniser to your UIView. That way it handles most of the setup code for you, and when it detects a pinch triggers a method.
Basic example in Objective-C:
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handlePinchGesture:)];
[self.view addGestureRecognizer:pinchGesture];
- (void)handlePinchGesture:(id)sender
{
NSLog(#"Recieved pinch");
UIPinchGestureRecognizer *senderGR = (UIPinchGestureRecognizer *)sender;
NSLog(#"Scale is: %f", senderGR.scale);
}
And in Swift:
let pinchGestureRecognizer = UIPinchGestureRecognizer.init(target: self, action: #selector(ViewController.handlePinchGesture(_:)))
self.view.addGestureRecognizer(pinchGestureRecognizer)
func handlePinchGesture(sender:AnyObject) {
print("Received pinch")
let senderGR = sender as! UIPinchGestureRecognizer
print("Scale is \(senderGR.scale)")
}
Related
I have used third party lib to show array of images in a slider . The images in an array comes from server, now i want to show the image in a bigger image view on a tap gesture. When anyone of the image user tap it should be shown in big imageview. I have tried some code but it is not working. My code is,
int i=0;
tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(expandImage:)];
tap.numberOfTapsRequired = 1;
[_ImageView setUserInteractionEnabled:YES];
[_ImageView addGestureRecognizer:tap];
tap = [_imagesData objectAtIndex:i];
NSLog(#"TTT %#",tap);
[self.view addSubview:_fullImage];
The method is ,
-(void)expandImage:(UITapGestureRecognizer*)recogniser
{
[self.view addSubview:_fullImage];
UIButton *closeButton = [[UIButton alloc]init];
[closeButton setTitle:#"Close" forState:UIControlStateNormal];
// [closeButton addTarget:self action:#selector(Closetab) forControlEvents:UIControlEventTouchUpInside];
[_fullImage addSubview:closeButton];
UIImageView *photoView = [[UIImageView alloc]init];
[photoView setBackgroundColor:[UIColor blueColor]];
[_fullImage addSubview:photoView];
// photoView.accessibilityIdentifier = #"nature2.png";
[_fullImage addSubview:_fullImage];
}
here I attached the sample project , customize yourself
step1
create the one full screen view for preview the image (use one UIView, one close btn, one imageview)
#interface ViewController () <UIScrollViewDelegate, TAPageControlDelegate>
{
NSTimer *timer;
NSInteger index;
//
IBOutlet UIImageView *imgfull;
IBOutlet UIView *fullimagevie;
IBOutlet UIButton *btnClose;
}
step2
add the gesture for tap the image event and set the frame of your duplicate view as bottom of viewcontroller
- (void)viewDidLoad
{
[super viewDidLoad];
[self setviewframe:self.view.frame.size.height + 10];
self.imagesData = #[#"image1.jpg", #"image2.jpg", #"image3.jpg"];
for(int i=0; i<self.imagesData.count;i++){
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.view.frame) * i, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.scrollView.frame))];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.image = [UIImage imageNamed:[self.imagesData objectAtIndex:i]];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(expandImage:)];
tap.numberOfTapsRequired = 1;
tap.view.tag = i;
[imageView setUserInteractionEnabled:YES];
[imageView addGestureRecognizer:tap];
[self.scrollView addSubview:imageView];
}
step3
handle the image tap for preview the image
-(void)expandImage:(UITapGestureRecognizer*)recogniser
{
imgfull.image = [UIImage imageNamed:[self.imagesData objectAtIndex:recogniser.view.tag]];
[UIView transitionWithView:fullimagevie
duration:0.4
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
[self setviewframe:0];
}
completion:NULL];
}
step4
dismiss the bigger image view on tap the close button
- (IBAction)btnClose:(UIButton *)sender {
[UIView transitionWithView:fullimagevie
duration:0.4
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
[self setviewframe:self.view.frame.size.height + 10];
}
completion:NULL];
}
step5
create the common method for set the frame for your bigger imageview
-(void)setviewframe:(CGFloat)coordinate{
CGRect modifyframe = fullimagevie.frame;
modifyframe.origin.y = coordinate;
fullimagevie.frame = modifyframe;
}
I have 3 image views and I would like to prevent simultaneous taps on image views. how can I do that? Can anyone help me??
for (int i=0; i <= [_images1 count]-1; i++){
CGFloat xOrigin = i * self.view.frame.size.width/3;
wordsImage = [[UIImageView alloc] init];
[wordsImage setFrame:CGRectMake(xOrigin+20, self.view.frame.size.height/3,self.view.frame.size.width/3.5 , self.view.frame.size.height/5)];
[wordsImage setImage:[UIImage imageNamed: [_images1 objectAtIndex:i]]];
[self.view addSubview:wordsImage];
[wordsImage setTag:i];
wordsImage.userInteractionEnabled = YES;
tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:index_image:)];
tapGesture1.numberOfTapsRequired = 1;
[tapGesture1 setDelegate:self];
[wordsImage addGestureRecognizer:tapGesture1];
}
Use this method to restrict the sequence of click your same imageview. I hope this will help you.
int previousTag,curentTag,flag;
-(void)tapGesture:(id)sender{
UIGestureRecognizer *recognizer = (UIGestureRecognizer*)sender;
UIImageView *imageView = (UIImageView *)recognizer.view;
if(flag == 0){
previousTag = imageView.tag;
curentTag = 520; // unequal value you will enter here
flag = 1;
}
else {
curentTag = imageView.tag;
}
if(previousTag != curentTag)
{
[imageView setImage:[UIImage imageNamed:#"anyImage.png"]];
previousTag = curentTag;
}
}
If you want to prevents simultaneous click on Imageviews, you can set exclusiveTouch by YES.
/* exclusiveTouch
A Boolean value that indicates whether the receiver handles touch events exclusively.
Setting this property to YES causes the receiver to block the delivery of touch events to other views in the same window. The default value of this property is NO.
*/
for (int i=0; i <= [_images1 count]-1; i++){
CGFloat xOrigin = i * self.view.frame.size.width/3;
wordsImage = [[UIImageView alloc] init];
[wordsImage setFrame:CGRectMake(xOrigin+20, self.view.frame.size.height/3,self.view.frame.size.width/3.5 , self.view.frame.size.height/5)];
[wordsImage setImage:[UIImage imageNamed: [_images1 objectAtIndex:i]]];
[self.view addSubview:wordsImage];
[wordsImage setTag:i];
wordsImage.userInteractionEnabled = YES;
wordsImage.exclusiveTouch = YES;//Set this property
tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:index_image:)];
tapGesture1.numberOfTapsRequired = 1;
[tapGesture1 setDelegate:self];
[wordsImage addGestureRecognizer:tapGesture1];
}
I hope this would be helpful
W hen you tap the image view set one Bool variable to true and manage that variable.
Can anyone help me ? I want to create dynamic text field in side a loop.I have been able to create and made it editable too. My requirements are in below.
i.I want to access each text fields value and make a sum of those will store in a Label.
ii. Let's say there are 5 dynamic created text fields having value (10,20,30,40,50).
so label displays sum of 5 value. ie. 10+20+30+40+50 = 150
if i make changes in either textfield values, it should recalculate and changes the total sum in label.
my logic goes as below.
-(void)create
{
myarr = [NSMutableArray arrayWithObjects:#"1000",#"2000",#"3000",#"4000",#"5000", nil];
int x = 20, y = 50;
int width = 280, height = 40;
for (int item=0; item<[myarr count]; item++)
{
edit_txt = [[UITextField alloc]initWithFrame:CGRectMake(x, y, width, height)];
edit_txt.text = [NSString stringWithFormat:#"%#",[myarr objectAtIndex:item]];
[edit_txt setTag:item+1];
edit_txt.placeholder = #"Click here to type";
edit_txt.borderStyle = UITextBorderStyleRoundedRect;
edit_txt.font = [UIFont systemFontOfSize:15];
edit_txt.textAlignment = NSTextAlignmentLeft;
edit_txt.returnKeyType = UIReturnKeyDefault;
edit_txt.delegate = (id)self;
[self.view addSubview:edit_txt];
y += height;
}
tot_txt = [[UITextField alloc]initWithFrame:CGRectMake(edit_txt.frame.origin.x, edit_txt.frame.origin.y + height + 10, width , height)];
tot_txt.placeholder = #"Total Value";
tot_txt.borderStyle = UITextBorderStyleRoundedRect;
tot_txt.font = [UIFont systemFontOfSize:15];
tot_txt.textAlignment = NSTextAlignmentLeft;
tot_txt.returnKeyType = UIReturnKeyDefault;
tot_txt.delegate = (id)self;
[self.view addSubview:tot_txt];
save_btn = [UIButton buttonWithType:UIButtonTypeCustom];
[save_btn setFrame:CGRectMake(tot_txt.frame.origin.x, tot_txt.frame.origin.y + height + 10, width , height)];
[save_btn setTitle:#"Save" forState:UIControlStateNormal];
[save_btn addTarget:self action:#selector(save_click:) forControlEvents:UIControlEventTouchUpInside];
[save_btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[self.view addSubview:save_btn];
CALayer *btnlayer = [save_btn layer];
[btnlayer setBorderColor:[UIColor redColor].CGColor];
[btnlayer setBorderWidth:0.3];
[btnlayer setCornerRadius:20.0];
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
int count = 0;
for (int item = 0; item < [myarr count]; item++)
{
UITextField *textField = ([[self.view viewWithTag:item + 1] isKindOfClass:[UITextField class]])?(UITextField *)[self.view viewWithTag:item + 1]:nil;
count += [textField.text intValue];
}
tot_txt.text = [NSString stringWithFormat:#"%d", count];
}
Thanks in advance.
Ajeet Kumar.
It would be more easy,
To access each text field (the scope is available only within the loop),you can use tag property of the text field.
Example:
for (int itemIndex = 1; itemIndex <= 5; itemIndex++)
{
UITextField *textField = [[UITextField alloc] initWithFrame:yourFrame];
//all properties assigning here
textField.tag = itemIndex; //assigning tag here(starts from 1).
textField.delegate = self;
[self.view addSubview: textField];
}
Now, here comes the calculation. Implement the UITextField delegates.
Write the <UITextFieldDelegate> in your .h file
#interface yourClassName : UIViewController <UITextFieldDelegate>
To calculate while end editing,
-(void)textFieldDidEndEditing:(UITextField *)textField
{
int count = 0;
for (int itemIndex = 1; itemIndex <= 5; itemIndex++)
{
UITextField *textField = ([[self.view viewWithTag:itemIndex] isKindOfClass:[UITextField class]])?(UITextField *)[self.view viewWithTag:itemIndex]:nil;
count += [textField.text intValue];
}
countLabel.text = [NSString stringWithFormat:#"%d", count];
}
To calculate while editing, implement delegate shouldChangeCharactersInRange and use the same code base.
Also implement the delegates textFieldShouldClear ,
textFieldShouldReturn and use the same code base.
Please make sure that, your view not holding any elements with the tag from 1 to 5 except these test fields.
Also, you can avoid the looping by applying your thoughts on it ;)
I did like this,
#import "ViewController.h"
#interface ViewController () <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate> {
UITableView* _tableView;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 100, 768, 600) style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
[self.view addSubview:_tableView];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"SomeCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SomeCell"];
UITextField* _textField = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, 600, 40)];
_textField.delegate = self;
_textField.tag = indexPath.row + 1;
[_textField setBackgroundColor:[UIColor lightGrayColor]];
[_textField addTarget:self action:#selector(onTextChange:) forControlEvents:UIControlEventEditingChanged];
[cell.contentView addSubview:_textField];
}
return cell;
}
- (void)onTextChange:(id)sender
{
double result = 0.0;
for (int itemIndex = 0; itemIndex < 5; itemIndex++) {
UITableViewCell* cell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:itemIndex inSection:0]];
UITextField* fooTF = (UITextField*)[cell.contentView viewWithTag:itemIndex + 1];
result += [fooTF.text doubleValue];
}
// update your lable here
NSLog(#"result %f", result);
//for sample
self.title = [NSString stringWithFormat:#"%f", result];
}
- (float)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
return 50.0;
}
- (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string
{
NSNumberFormatter* nf = [[NSNumberFormatter alloc] init];
[nf setNumberStyle:NSNumberFormatterNoStyle];
NSString* newString = [NSString stringWithFormat:#"%#%#", textField.text, string];
NSNumber* number = [nf numberFromString:newString];
//allow only numbers
if (number)
return YES;
else
return NO;
}
I am making a custom control which consists of UIImageView and Label. The control behaves like a checkbox.
Here is the code:
-(instancetype) initWithTitle:(NSString *)title normalCheckBoxImage:(NSString *)normalCheckBoxImage selectedCheckBoxImage:(NSString *)selectedCheckBoxImage
{
self = [super init];
self.userInteractionEnabled = YES;
self.normalCheckBoxImageName = normalCheckBoxImage;
self.selectedCheckBoxImageName = selectedCheckBoxImage;
self.title = title;
[self setupSubViews];
[self registerGestureRecognizers];
return self;
}
-(void) registerGestureRecognizers
{
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(checkBoxTapped:)];
singleTapGestureRecognizer.delegate = self;
singleTapGestureRecognizer.numberOfTapsRequired = 1;
[self.checkBoxImageView addGestureRecognizer:singleTapGestureRecognizer];
}
-(void) checkBoxTapped:(UITapGestureRecognizer *) recognizer
{
self.isChecked = !self.isChecked;
if(self.isChecked)
{
[self.checkBoxImageView setImage:[UIImage imageNamed:self.selectedCheckBoxImageName]];
}
else
{
[self.checkBoxImageView setImage:[UIImage imageNamed:self.normalCheckBoxImageName]];
}
}
-(void) setupSubViews
{
self.checkBoxImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.normalCheckBoxImageName]];
self.checkBoxImageView.frame = CGRectMake(0, 0, 50, 50);
NSLog(#"width = %f; height = %f",self.checkBoxImageView.frame.size.width,self.checkBoxImageView.frame.size.height);
[self.checkBoxImageView setUserInteractionEnabled:YES];
// The init with frame should be replaced by the NSConstraints
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.checkBoxImageView.frame.size.width + 5, 10, 100, 20)];
self.titleLabel.text = self.title;
[self addSubview:self.checkBoxImageView];
[self addSubview:self.titleLabel];
}
I have attached gesture recognizer to the UIImageView. But for some reason it only fires when I am close to the left edge of the UIImageView. I am not sure what I am doing wrong. If I touch in the middle of the uIImageView then it does not do anything.
Here is the image:
The problem was the frame for the super view was not correct. Instead of width and height of 50 X 50 it was 50 X 20.
AZCheckBox *checkbox = [[AZCheckBox alloc] initWithTitle:#"I agree" normalCheckBoxImage:#"NormalCheckBoxImage" selectedCheckBoxImage:#"SelectedCheckBoxImage"];
checkbox.frame = CGRectMake(100, 100, 200, 50);
checkbox.delegate = self;
[self.view addSubview:checkbox];
I am trying to make a game that recognizes when a person is holding down his/her finger and moves a player when it is held down. On top of this, I am trying to create a back button in order to go back to the home screen.
This is my code for these two things:
- (void) didMoveToView:(SKView *)view {
holdingFinger = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
holdingFinger.minimumPressDuration = 0;
holdingFinger.numberOfTapsRequired = 0;
holdingFinger.numberOfTouchesRequired = 1;
holdingFinger.allowableMovement = 100;
[view addGestureRecognizer:holdingFinger];
changeScene = [UIButton buttonWithType:UIButtonTypeSystem];
[changeScene addTarget:self action:#selector(changeScene) forControlEvents:UIControlEventTouchUpInside];
[changeScene setTitle:#"Home" forState:UIControlStateNormal];
changeScene.backgroundColor = [UIColor whiteColor];
changeScene.frame = CGRectMake(410, 0, 70, 30);
[self.view addSubview:changeScene];}
- (void)handleLongPress:(UILongPressGestureRecognizer*)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
//NSLog(#"isHoldingDown = YES");
isHoldingDown = YES;
} else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
//NSLog(#"isHoldingDown = NO");
isHoldingDown = NO;
}}
- (void) changeScene {
[changeScene removeFromSuperview];
SKScene* nextScene = [[ATOpenScene alloc] initWithSize:self.size];
SKTransition* transition = [SKTransition doorsOpenVerticalWithDuration:0.5];
[self.view presentScene:nextScene transition:transition];
}
Both of these things work as I want them to on their own, however, when I put them both in, I am unable to press the button. Is there a simple fix / a careless mistake that I am making here? And if so what would it be? Thanks for the help.
Your holdingFinger.minimumPressDuration = 0; should be greater than 0 to work with the tapgesture