Dragging a tableview cell that contains uibuttons - objective-c

I'm trying to implement a uitableview that its rows can be dragged to right and left (and show something behind them).
The code works fine, I've implemented it using the following methods:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
My problem is that the rows also contain UIButtons that when clicking them- should be clicked but when dragging - should drag the entire cell.
I've found this solution. Basically to bubble up the events when clicking on the UIButtons:
[super touchesBegan:touches withEvent:event];
[self.nextResponder touchesBegan:touches withEvent:event];
But, it seems taht the event touchesMoved only bubbles once.
I've seen all sort of questions in this area. Example. But I don't see any solution or responses.
Any help, suggestion or creative workaround would be appreciated!

Instead of implementing touchesBegan, etc. why not use a UIPanGestureRecognizer? I tested this with just a simple rectangular view which was mostly covered by a UIButton. The view was dragged, no matter where I touched, and the button method fired if I clicked over the button.
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanGesture:)];
[self.theView addGestureRecognizer:panGesture]; //theView is IBOutlet for small view containing a button
}
-(void)viewDidAppear:(BOOL)animated {
self.currentViewFrame = self.theView.frame;
}
- (IBAction)handlePanGesture:(UIPanGestureRecognizer *)sender {
CGPoint translate = [sender translationInView:self.view];
CGRect newFrame = self.currentViewFrame;
newFrame.origin.x += translate.x;
newFrame.origin.y += translate.y;
sender.view.frame = newFrame;
if (sender.state == UIGestureRecognizerStateEnded)
self.currentViewFrame = newFrame;
}
-(IBAction)doClick:(id)sender {
NSLog(#"click");
}

Just check to see which one was touched using the tag system.

Related

NSUndoManager with TouchesEnded for MKPolyline

This is my first time trying to use NSUndoManager and i'm not sure where I should be putting it/what i'm missing. I'm making an application that has a map view with a draw button and undo button. I have the draw button enable the user to draw a polyline and every time their finger leaves the screen it connects another line to the line they just drew. I want the undo button to get rid of the last line that they drew.
some of what I have so far...
- (void)viewDidLoad
{
[super viewDidLoad];
...
...
undoManager = [[NSUndoManager alloc]init];
}
- (IBAction)oopsButton:(id)sender {
[undoManager undo];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
....
....
[[undoManager prepareWithInvocationTarget:self]touchesEnded:(touches) withEvent:event];
[undoManager setActionName:NSLocalizedString(#"Route Changed", #"route undo")];
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
...
...
right now, when I click undo, it undoes one line but that's all. I need it to keep undoing for as many times as the user clicks. Thanks for any help on this, i've been looking all over google and stack and haven't found anything that helps yet.
I found a way to update the polyline without using undo manager...
- (IBAction)oopsButton:(id)sender {
//remove last point from array
[self.coordinates removeLastObject];
//update line on map
NSInteger numberOfPoints = [self.coordinates count];
if (numberOfPoints > 1)
{
MKPolyline *oldPolyLine = self.polyLine;
CLLocationCoordinate2D points[numberOfPoints];
for (NSInteger i = 0; i < numberOfPoints; i++)
points[i] = [self.coordinates[i] MKCoordinateValue];
MKPolyline *newPolyLine = [MKPolyline polylineWithCoordinates:points count:numberOfPoints];
[self.mapView addOverlay:newPolyLine];
self.polyLine = newPolyLine;
if (oldPolyLine)
[self.mapView removeOverlay:oldPolyLine];
}
}

Hiding Keyboard in xcode storyboard

New to xcode,i'm creating a simple login form in xcode 4.2 and i would like to hide the keyboard,i have the correct code i think,from the tutorial it says i need to change the class of the view to UIControl but there is no option for this, is there another way when working with storyboards?
- (IBAction)backGroundTouched:(id)sender
{
[emailTextField resignFirstResponder];
[passTextField resignFirstResponder];
}
Assuming you are doing them inside the viewCotroller, invoke
[self.view endEditing:YES];
If your two text fields are subviews of some higher-level view you can also use [higherLevelView endEditing]; and not care which subview is currently active.
Make sure your both text fields is connect with it's IBOutlets.
No need to change UIView to UIControl.
// Connect every textfield's "Did end on exit" event with this method.
-(IBAction)textFieldReturn:(id)sender
{
[sender resignFirstResponder];
}
// Use this method also if you want to hide keyboard when user touch in background
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[emailTextField resignFirstResponder];
[passTextField resignFirstResponder];
}
I followed this tutorial: http://www.techotopia.com/index.php/Writing_iOS_7_Code_to_Hide_the_Keyboard and it's working for me:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([_textField isFirstResponder] && [touch view] != _textField) {
[_textField resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}

Retrieve and change the point at which touchUpInside changes to touchUpOutside

I have made a UISlider work just like the "slide to unlock" slider.
What I need to do is determine the point at which lifting your finger off is classed as touchUpOUTSIDE and not touchUpINSIDE. This is the point where you slide your finger past the end of the slider too far.
I guess it's the same as with a UIButton, you can press the button then slide your finger off the button and depending how far you go, it can still be classed as touchUpInside.
If possible, i'd like to mark the target area with a circle.
Once i've managed to find where this point is, is it possible to change it? So I could have a bigger target area?
I really don't know where to start with this. Thanks
According to the docs, the UIControlEventTouchUpOutside event is triggered when the finger is outside the bounds of the control. If you're trying to change that area, the slider will scale with it. Why not just tie the action for UIControlEventTouchUpOutside to the same as UIControlEventTouchUpInside?
It's taken me a few hours, but i've managed to sort this.
I've done a lot of testing overriding touchesMoved, touchesEnded and sendAction:action:target:event and it seems that any touch within 70px of the frame classes as a touch INSIDE. So for a UISlider that's 292x52 any touch from x:-70 to x:362 or y:-70 to 122 will count as an inside touch, even though it's outside the frame.
I have come up with this code that will override a custom class to allow a bigger area of 100px around the frame to count as an inside touch:
#import "UICustomSlider.h"
#implementation UICustomSlider {
BOOL callTouchInside;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
callTouchInside = NO;
[super touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint touchLocation = [[touches anyObject] locationInView:self];
if (touchLocation.x > -100 && touchLocation.x < self.bounds.size.width +100 && touchLocation.y > -100 && touchLocation.y < self.bounds.size.height +100) callTouchInside = YES;
[super touchesEnded:touches withEvent:event];
}
-(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
if (action == #selector(sliderTouchOutside)) { // This is the selector used for UIControlEventTouchUpOutside
if (callTouchInside == YES) {
NSLog(#"Overriding an outside touch to be an inside touch");
[self sendAction:#selector(UnLockIt) to:target forEvent:event]; // This is the selector used for UIControlEventTouchUpInside
} else {
[super sendAction:action to:target forEvent:event];
}
} else {
[super sendAction:action to:target forEvent:event];
}
}
With a little bit more tweaking I should be able to use it for the opposite also. (Using a closer touch as an outside touch).

single tab on uitextview when in edit mode, close keyboard

I want to close the keyboard, when a user do a single tap on uitextview and when he is in edit mode. Does anyone know how to do that?
touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event is not fired.
I can't use the textViewDidBeginEditing though.
Have included UITextViewDelegate in my header file. In .m file, I have set the delegate as self.textView.delegate = self and below is the code to capture touch event
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
if([self.textView isFirstResponder])
{
[self.textView resignFirstResponder];
}
}
But it is not getting called by the textView I am using.
When using Pinch and touch events you have to initialize the touch event. I can't remember of the top of my head but it is something like
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:nil];
tap.numberOfTapsRequired = 1;
put this in your viewDidLoad and then touchesBegan should get called when you tap the screen, Oh don't forget to add the (tapGesture) to the view like so
[self.view addGestureRecognizer:tapGesture];
Hope this helps.

resign keyboard when losing focus on uisearchbar

I'm making an UISearchBar option in the navigationbar of my app.
My app consists of multiple views and subviews.
I have this mainview which has 3 other views on himself. one of it is empty (for now) the other 2 have tableviews on them.
I want my keyboard to show when I'm searching and hide when i'm doing the actual search or when i touch/click outside the uisearchbar.
Im using the searchbardelegate as is required.
Im able to hide the keyboard using [searchBar resignFirstResponder] in the following ways.
When im pressing the return key.
When i cancel search manually
When i press any of the keyboard buttons to search or cancel.
When i touch an empty part of the screen using
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if ([mySearchBar isFirstResponder] && [touch view] != mySearchBar) {
[mySearchBar resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}
What i not seem to be able to do is make it respond to touching one of my 2 tableviews. Or when im refilling the mainview to contain something different entirely.
Ive tried changing the touchesbegan method to resign the searchbar when touching the tableviews but it hasnt worked so far.
I've tried several other things found by my dear friend mr. google, but it all seems to be something other then I need.
Anyone have any ideas of what I might do to fix this problem?
EDIT:
It appears so that, when using breakpoints, touchesbegan-method does respond to the backgroundview but it doesnt respond when i touch either of the tableviews or the navigationbar (containing the uisearchbar).
Solved it!
- (BOOL) searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
[self.myViewController1.customView1 setUserInteractionEnabled:NO];
[self.myViewController2.customView2 setUserInteractionEnabled:NO];
[searchBar setShowsCancelButton:YES animated:[mySettings animation]];
return YES;
}
I started by shutting down the userInteraction on my 2 subviews, at the moment I start using the searchBar.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if ([self.mySearchBar isFirstResponder] && [touch view] != self.mySearchBar)
{
[self.mySearchBar resignFirstResponder];
[self.myViewController1.customView1 setUserInteractionEnabled:YES];
[self.myViewController2.customView2 setUserInteractionEnabled:YES];
}
[super touchesBegan:touches withEvent:event];
}
Then when I click/tap/touch outside the searchBar I first resign the keyboard which is first responder still AND AFTER that I set userInteraction back on for the 2 subviews.
The order of doing this is vital!
This piece of code allows u to resign the keyboard in a single mainViewController even when it is crowded with a massload of subviews.
Have you tried this,
UISearchBar *searchBar;
Next set the Getter and Setter Property of UISearchBar.
and call the any method
[searchBar resignFirstResponder];