In my app I have a UIWebView that shows a list of pictures. Right now, when someone taps and holds their finger on a picture, the option comes up to copy that picture.
Is there a way to make it so that, when someone taps and holds, the option to save that picture appears?
Any ideas are welcomed!
You need to detect the long tap. For that you need to add:
#property (nonatomic,strong) UILongPressGestureRecognizer *lpgr;
and in your view did load:
self.lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPressGestures:)];
self.lpgr.minimumPressDuration = 1.0f;
self.lpgr.allowableMovement = 100.0f;
[self.view addGestureRecognizer:self.lpgr];
and ask the user to save the picture once the app detects the long tap.
- (void)handleLongPressGestures:(UILongPressGestureRecognizer *)sender
{
if ([sender isEqual:self.lpgr]) {
if (sender.state == UIGestureRecognizerStateBegan)
{
//prompt the user to save the picture .
}
}
}
Related
I have some questions. I'm a total novice to Objective-c and Xcode's development.
My problem is the following:
I have a button with an IBActions (cambia view) and an Outlet (gioca_outlet).
This button is connected to another view by the "Show", so when I press the next view appears.
But, before changing view I'd like to commit animations with the button, which has its own image.
I'd like to scale the button's image size (maintaining the same center) for 1/2 seconds, then show the second view.
I'd also like the button's size to be the initial one when I skip back to the main view.
So, I came up with this code:
- (IBAction)cambiaview:(id)sender {
[UIView animateWithDuration:2.0 delay:0.4 options:UIViewAnimationOptionTransitionCrossDissolve animations:{
[_gioca_outlet setCenter:CGPointMake([_gioca_outlet.center].x + 0.0001, [_gioca_outlet.center].y +0.0001)];
[_gioca_outlet setTransform:CGAffineTransformScale(_gioca_outlet.transform, 2.0, 2.0)];}
completion:^(BOOL finished) {
};
}
Back button, to return to the main view:
- (IBAction)back:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{ //
}];
}
Thanks.
Open Interface Builder and delete all existing connections between two view controllers.
Then ctrl+drag from first view controller to the second and choose "Show" option.
step 1
After that click on the created connection (it's called segue), switch to Attributes Inspector and give it an ID step 2
In the completion block of your animation write [self performSegueWithIdentifier:#"showNextView"];
You have connected the button's action segue with the second view, so as soon as you clicked on the button, next view appears. Instead, you connect a segue from viewcontroller1 to viewcontroller2 and give an identifier to your segue.
Then on button's click event, add this code.
- (IBAction)cambiaview:(id)sender
[UIView animateWithDuration:0.8 animations:^{
//this will transform your button to grow a little bit bigger
_gioca_outlet.transform = CGAffineTransformMakeScale(1.5, 1.5);
}completion:^(BOOL finished) {
//push from viewcontroller1 to viewcontroller2 using you segue identifier
[self performSegueWithIdentifier:#"vc1tovc2segue" sender:self]
}];
This code will make your button a little bit bigger animatedly and then pushes to second view controller.
Now, if you want to play an audio, you can play it in second view controller's viewDidLoad method using AVFoundation framework.
To play the sound file do the following:
Add your sound file in your projects directory.
Import AVFoundation framework by writing,
#import <AVFoundation/AVFoundation.h>
Create a strong property of AVAudioPlayer in .h of your viewcontroller2.
#property (strong, nonatomic) AVAudioPlayer *player;
Then in viewcontroller2's viewDidLoad add this code to play the audio file,
- (void)viewDidLoad {
[super viewDidLoad];
//SampleAudio is your audio file name and mp3 is your extension.
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"SampleAudio" ofType:#"mp3"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
self.player.delegate = self;
[self.player play];
}
To make the button's size normal when you come back to your first view controller, add this code in your first view controller:
-(void)viewWillAppear:(BOOL)animated
{
_gioca_outlet.transform = CGAffineTransformIdentity;
}
Hope this helps.
If you face any problem understanding anything, feel free to leave a comment. :)
I have a very strange issue, UITextView touch event crash on double tap whereas same code works with < iOS10 version. (It means below iOS10 version there is no crash for press gesture recognizer)
Actually, I am adding the double tap and log press gesture based on permission. If the user has permission to comment then add gestures in viewDidLoad methods. Comment is allowed only with double tap or long press
singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureAction:)];
singleTapGesture.numberOfTapsRequired = 1;
// adding gesture to open window for commenting only when he has writing access
if (canComment) {
longPressgesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressGestureAction:)];
longPressgesture.minimumPressDuration = 0.2;
doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doDoubleTap:)];
doubleTap.numberOfTapsRequired = 2;
}
On single tap
-(void)singleTapGestureAction:(UITapGestureRecognizer*)tapGestureRecognizer{
if (isSingleTapped) {
isSingleTapped = NO;
return;
}
isSingleTapped = YES;
UITextView *textView = (UITextView *)tapGestureRecognizer.view;
[self.commentView becomeFirstResponder]; // becomeFirstResponder
}
On double tap
-(void)doDoubleTap:(UITapGestureRecognizer*)tapGestureRecognizer
{
UITextView *textView = (UITextView *)tapGestureRecognizer.view;
[self.commentView becomeFirstResponder]; // becomeFirstResponder
// To show the UIMenuController menu
[self setCommentMenuToolTipWithRect:completeRect];
}
NOTE: I am adding [self.commentView becomeFirstResponder]; on every gesture action
UITextView delegate methods
- (void)textViewDidBeginEditing:(UITextView *)inView
{
[self.commentView becomeFirstResponder];
range=[self.commentView selectedRange];
}
USE CASE:
When I double tap to select any word then APP CRASH and UIMenuController does not appear,
but if I add the following line app does not crash
- (void)textViewDidChangeSelection:(UITextView *)textView{
[textView resignFirstResponder];
} // app does not crash
and UIMenuController appears with comment menu items that's great. I was happy that I have fixed the crash issue.
But there is another problem, when I press outside, menu hides and
select any word AGAIN then It does not appear SECOND time.
I have tried all the possible way to show the menu for returns
YES/TRUE to canBecomeFirstResponder. I know, there has to be a view
that claims firstResponder for the menu to show. but how ?
On second time touch, not even calling any gesture recognizer method
From the logs it is clear that when double tap is recognized, same touch update is also sent to another gesture recognizer, which fails.
So, a simple solution would be to avoid detection of other gestures on double tap.
This can simply be achieved by making all other gestures on commentView require doubleTap to fail using requireGestureRecognizerToFail. just add the condition in addGestureToTextView method as shown below.
if (withDoubleTap && self.canScreenPlayEdit) {
[self.commentView removeGestureRecognizer:singleTapGesture];
[self.commentView addGestureRecognizer:doubleTap];
[self.commentView addGestureRecognizer:longPressgesture];
for (UIGestureRecognizer *recognizer in self.commentView.gestureRecognizers) {
[recognizer requireGestureRecognizerToFail:doubleTap];
}
}
This does solve the crash and also shows the menu without calling resignFirstResponder in textViewDidChangeSelection.
However, there seem to be many issues in your code. PLSceneDetailsVC is too complicated and you need to simplify the code. You need to streamline the gesture management or you will end up facing many more such issues.
longPressgesture.minimumPressDuration = 0.2;
My guess the problem is here. 0.2s is way too small to be used for longPress. Probably both were triggered (longPress and double tap).
Change it to higher like 1.5s.
I have an app with a camera. The user presses a button and the view changes to the camera view.
In the cameraView, I put the pickerControl in the viewDidLoad.
When the view appears, the camera opens and allows the user to take a picture. When done, the user can choose to keep the photo and if he does, the camera view dismisses and in that moment, I can see the picture I've taken in the image viws I created but the camera keeps opening up.
I think it's because I have my pickerControl in my viewDidLoad and every time the camera dismisses, because of that, it repeatedly keeps opening the camera. Is there any way around this?
Here is my cameraViewController that loads when the user selects the camera option
- (void)viewDidLoad
{
[super viewDidLoad];
}
// When the view appears, the camera will turn on
-(void)viewDidAppear:(BOOL)animated
{
// Initialize the picker control
UIImagePickerController *pickerControl = [[UIImagePickerController alloc] init];
// If all's good, start up the camera
if ((pickerControl != nil)&&(picHolder == nil))
{
pickerControl.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerControl.delegate = self;
pickerControl.allowsEditing = true;
}
// Camera turns on
[self presentViewController:pickerControl animated:true completion:nil];
}
Im not sure how to prevent the view from loading every time when that is what opens the camera in the first place.
Thank You
Add a BOOL ivar to your class. Some pseudocode below
YourController {
BOOL didShow;
}
-(void)viewDidAppear:(BOOL)animated {
if (!didShow) {
// present the UIImagePickerController
}
didShow = YES;
}
I have a UIPickerView set up with an attached toolbar button that should allow the user to switch from a picker view to a keyboard view. The pickerView should slide down and a keyboard should slide up in it's place... Theoretically.
The pickerView appears when a user clicks the text field in textFieldDidBeginEditing.
elementPicker = [[UIPickerView alloc] init];
[elementPicker setDelegate:self];
elementPicker.showsSelectionIndicator = YES;
...
[_itemElementField setInputView:elementPicker];
When the user clicks the "Use Keyboard" button, I have a method to dismiss the picker and call the keyboard. I can dismiss the pickerview without a problem but CANNOT DISPLAY THE KEYBOARD!!
HELP!
Here is the method called when the user wants the keyboard:
-(void)useKeyboardClicked:(id)sender {
NSLog(#"'USE KEYBOARD' BUTTON CLICKED");
// DISMISS THE PICKER VIEW
[elementPicker removeFromSuperview];
[_itemElementField resignFirstResponder];
_itemElementField.inputAccessoryView = nil;
// SET ELEMENTPICKER TO THE DEFAULT KEYBOARD
elementPicker = UIKeyboardTypeDefault;
[_itemElementField setInputView:elementPicker];
// SHOW KEYBOARD
[_itemElementField becomeFirstResponder];
}
I'm grasping at straws now and need some help! I've even gone so far as to try to define a keyboard in the header file with
#property (strong, nonatomic) IBOutlet UIKeyboard *elementKeyboard;
but that doesn't work AT ALL.
for those that might have this issue in the future, the answer ends up being quite simple.
You need to reload the input view after resetting it to a keyboard with reloadInputViews.
Here's the code:
-(void)useKeyboardClicked:(UITextField *)sender {
NSLog(#"'USE KEYBOARD' BUTTON CLICKED");
[_itemElementField setInputView:UIKeyboardTypeDefault];
[_itemElementField becomeFirstResponder];
[_itemElementField reloadInputViews];
}
Here Is Solution Firstly you have to declare boolean variable checkFlag to keep record of useKeyboardClicked:
then
-(void)useKeyboardClick:(id)sender
{
if (checkFlag) {
checkFlag=false;
[txtField setInputView:nil];
[txtField reloadInputViews];
[txtField setKeyboardAppearance:UIKeyboardAppearanceDefault]; //you can set UIKeyboardAppearnce as Dark,light, alert instead of Default
[txtField setKeyboardType:UIKeyboardTypeDefault]; // you set decimal keyboard
} else {
checkFlag=TRUE;
[txtField setInputView:nil];
[txtField setInputAccessoryView:numberToolbar];
[txtField setInputView:pickerView];
}
}
One thing i m not total wrong but i can't set back picker view instead keyboard ..... try this i gave you hint ...
My app is crashing in the iPad simulator when I press the action button again once it has already been pressed to open my activity view. I am concerned that this will be an issue if the user wants to press the button again to close the Popover rather than touching outside of it. Any suggestions are appreciated :)
FYI the Action button is a UIToolbar button.
In the .h
#property (strong, nonatomic) UIPopoverController *popup;
#property (strong, nonatomic) UIPopoverController *activityViewProp;
In the .m:
-(IBAction)openUIActivityView:(id)sender {
UIActivityViewController *activityView = [[UIActivityViewController alloc]initWithActivityItems:#"Hello World" applicationActivities:nil];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:activityView animated:YES completion:^{
}];
} else {
self.popup = [[UIPopoverController alloc] initWithContentViewController:activityView];
[self.popup presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES]; }}
Just check if you already have a popup, and do something else
-(IBAction)openUIActivityView:(id)sender {
if (self.popup) {
[self.popup dismiss ...];
}
else {
// show popup code
}
}
The problem is, a view controller can only present one other view controller at any given time. Currently, when your tap the button a second time, you try to present a new instance of UIActivityViewController, while an other is already presented.
You can fix this, by checking the value of your main view controller's presentedViewController property. If it is not nil (and actually of type UIActivityViewController) you can return from the action without doing anything:
- (IBAction)openUIActivityView:(id)sender {
if (!self.presentedViewController) {
// We have no presented view controller yet.
// <your current code here>
} else {
// We are already presenting a view controller.
// Either dismiss it, or don't do anything.
}