UISwipeGestureRecognizer for subviews (UIVIew) not working - iphone

I have a View Controller with 3 subviews inside the self.view.
I'm trying to slide between them and it's not working.
Here is my code:
- (void)viewDidLoad
{
UISwipeGestureRecognizer *swipeGestureRecognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(didSwipe:)];
swipeGestureRecognizerLeft.direction = UISwipeGestureRecognizerDirectionLeft;
for (UIView *subview in self.view.subviews)
{
if([subview isKindOfClass:[UIView class]] && !([subview isKindOfClass:[UIImageView class]]))
{
[subview addGestureRecognizer:swipeGestureRecognizerLeft];
NSLog(#"Load 2");
}
}
}
-(void) didSwipe:(UISwipeGestureRecognizer *) swipeRecognizer {
NSLog(#"Load swipe");
if (swipeRecognizer.direction==UISwipeGestureRecognizerDirectionLeft)
{
NSLog(#"swipe Left");
[self SlideToLeft];
}
}
I really see that "Load 2" is being printed 3 times but when I try to slide it's not working.
Thank you

Are you using a UIScrollView here? That could be the problem.
I think you can just use the standard UIScrollView delegate methods in this situation:
- (void) scrollViewDidScroll: (UIScrollView *) sender
{
NSLog(#"Scrolled!");
}
Otherwise these guys here, here and here had some trouble too, maybe the answers there could help you.
If you're not using a UIScrollView here? I should use one, why not? 3 Subviews and swiping to the next one sounds just like a nice UIScrollView example (use paging).
Good Luck!

Related

How can i set content offset on multiple scrollviews with one method?

I am having a little problem. I want to make all my scrollview scroll to the top when I press a UITableViewCell. Following is the code in didSelectRowAtIndexPath:
[self.tableView setContentOffset:CGPointZero];
[verbTableView setContentOffset:CGPointZero];
[seinhabenScrollView setContentOffset:CGPointZero];
[mdhPresensScroll setContentOffset:CGPointZero];
[mdhPreteritumScroll setContentOffset:CGPointZero];
[mhdScroll setContentOffset:CGPointZero];
....
There are more of those scrollview, and I want to put the all in one single object or something... I have tried following code:
for (UIScrollView *scrolls in topLayer.subviews)
{
[scrolls setContentOffset:CGPointZero];
}
Thanks!
The basic idea is right. It just depends upon how you identify the scroll views. You could do something like the following, which explicitly tests whether the subview is a kind of UIScrollView:
for (UIScrollView *scrollView in self.view.subviews)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
Or you can explicitly reference the specific scrollviews in question (in which case the class membership test isn't strictly needed):
for (UIScrollView *scrollView in #[seinhabenScrollView, mdhPresensScroll, mdhPreteritumScroll])
{
scrollView.contentOffset = CGPointZero;
}
Or, if you create an IBOutletCollection in IB, you can use that, too:
for (UIScrollView *scrollView in self.scrollViews)
{
[scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
}
(Note, in that final example, I'm scrolling to the location in question with animation, providing the user some visual cue as to what just happened; that's completely up to you.)
In a comment above, you say that topView has subviews which, themselves, have subviews that are scrollviews, you'd have to do something like the following to handle this subview-of-subview situation:
for (UIView *subview in topLayer.subviews)
{
for (UIScrollView *scrollView in subview)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
}
Avoiding the dynamic type check, just place the views that can scroll into an array. Then, a little fancier, add an extension to scroll view so they can scroll to zero using no params, that let's us do the scrolling with an NSArray one-liner (makeObjectsPerform...)...
#interface UIScrollView (ScrollToZero)
- (void)scrollToZero; // a no-param method for scrolling to zero offset
#end
#implementation UIScrollView (ScrollToZero)
- (void)scrollToZero {
[self setContentOffset:CGPointZero animated:YES];
}
#end
NSArray *allMyScrolls = #[verbTableView, seinhabenScrollView, // and so on. put ONLY scrollViews in here
// you can make this array a property, initialized when the views are created
[allMyScrolls makeObjectsPerformSelector:#selector(scrollToZero)];

How to make custom button and cell shading for moving rows in UITable?

How can make custom button for moving rows in UITable?
I would like it to be transparent.
(Instead of this: )
Another thing is, when the cell is moved, it has shadow. Is it possible to remove it?
Try this...
You have to do this by subclassing UITableViewCell and overriding its setEditing:animated: method as follows:
The re-order control is a UITableViewCellReorderControl, but that's a private class, so you can't access it directly.
you could just look through the hierarchy of subviews and find its imageView.
- (void) setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing: editing animated: YES];
if (editing) {
for (UIView * view in self.subviews) {
if ([NSStringFromClass([view class]) rangeOfString: #"Reorder"].location != NSNotFound) {
for (UIView * subview in view.subviews) {
if ([subview isKindOfClass: [UIImageView class]]) {
((UIImageView *)subview).image = [UIImage imageNamed: #"yourimage.png"];
}
}
}
}
}
}
You can turn off the reordering control by setting -[UITableViewCell setShowsReorderControl:] to NO. After that you will need your own custom reordering implementation. I'm not sure what you can do about the shadow effect during a move.
If you really want to dig deep you can create your custom table view cell move UX.

UIScrollView scrollToTop not getting called for iPhone

I have a universal app, the code is the same. I have a UIScrollView in which has the scrollToTop working on the iPad but not on iPhone. I am pretty frustrated by this.
I know there's a similar thread posted here, but that is not the case. I used to have the scrolling to work before this both on the iPad and iPhone. Any idea what to look for?
The structure of the code is like this. I have a mainVC called A. I then have a VC called B. There is also another VC called C, which has a UIScrollView. I added C as B's child view controller. and then B as A's child VC. Now the scroll view on C did not have the scrollToTop working.
The delegate scrollViewShouldScrollToTop is also called only in the iPad, not in the iPhone.
Take a look at my answer to the question you've talked about. I've just added it a moment ago.
EDIT
I don't have the original code I've made, but it should be like that:
-(void)cleanUp:(UIScrollView*)view{
if([view isKindOfClass:[UIScrollView class]]){
view.scrollsToTop = NO;
}else{
for(UIScrollView* subview in view.subviews){
if([subview isKindOfClass:[UIView class]]){
[self cleanUp:subview];
}
}
}
}
and you can call it like this:
[self cleanUp:self.view];
You may also need even more tough variant of that routine (sometimes you may have a tableView inside a scrollView or something like that):
-(void)cleanUp:(UIScrollView*)view{
if([view isKindOfClass:[UIScrollView class]]){
view.scrollsToTop = NO;
}
for(UIScrollView* subview in view.subviews){
if([subview isKindOfClass:[UIView class]]){
[self cleanUp:subview];
}
}
}
I Just took the solution of #Ariel and done some improvements I want to share with you:
+ (void)globalDisableScrollToTop:(UIView *)_view;
{
// Check whether we got a scroll view
if ([_view isKindOfClass:[UIScrollView class]])
{
// Disable scroll to top
((UIScrollView *)_view).scrollsToTop = NO;
}
// Iterate all subviews
for (UIView *view in _view.subviews)
{
// Recursive call of this method
[self globalDisableScrollToTop:view];
}
}
Or without comments:
+ (void)globalDisableScrollToTop:(UIView *)_view;
{
if ([_view isKindOfClass:[UIScrollView class]])
((UIScrollView *)_view).scrollsToTop = NO;
for (UIView *view in _view.subviews)
[self globalDisableScrollToTop:view];
}
It now fixes all subviews and could be implemented as static method (of your root scroll view class).
If possible, Please paste the add subview code here. Looks like the problem is the view on which the scrollview is present is getting hide behind other view. Try changing the sequence of adding subview. Or you may also try bringSubviewtoFront property for setting the scrollview on top.
Let me know if it helps.

UILongPressGestureRecognizer stop handle without stop touching

I'm using UILongPressGestureRecognizer class to handle if one item is being selected.
The logic is as follows: User press during 1 second an item (UIView subclass). Once the gesture is detected, the item is highlighted and moveable.
The user must move this item across the screen without stop touching it.
The problem I'm facing is the gesture recognized shadows touchesBegan/Move/Ended necessary for the item class to arrange the movement.
I tried to remove the gesture recognized once is detected and the item selected. But still sending messages to the handle of gesture instead of call touches methods.
Anyone knows any way to stop "listening" the gesture recognizer without leave the finger of the screen?
Thanks.
Here the code:
-(void)addGestures
{
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleLongPress:)];
longPress.minimumPressDuration = iItemLongPressTime;
[self addGestureRecognizer:longPress];
[longPress release];
}
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
NSLog(#"Long press Ended");
}
else {
if (self.isSelected) return;
if ([delegate respondsToSelector:#selector(singleTouch:)])
[delegate singleTouch:self];
[self removeGestureRecognizer:[self.gestureRecognizers objectAtIndex:0]];
NSLog(#"Long press detected.");
}
}
As you can see in the else branch the delegate calls enables all procedures to mark this item as selected, and just after remove the recognizers.
What I'm missing?
--EDIT--
Done! This works:
#pragma mark Gesture Functions
-(void)addGestures
{
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleLongPress:)];
longPress.minimumPressDuration = iItemLongPressTime;
[self addGestureRecognizer:longPress];
[longPress release];
}
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
NSLog(#"Long press Ended");
}
else {
NSLog(#"Long press detected.");
if (self.isSelected) return;
if ([delegate respondsToSelector:#selector(singleTouch:)])
[delegate singleTouch:self];
[sender removeTarget:self action:#selector(handleLongPress:)];
sender.enabled = NO;
[self removeGestureRecognizer:sender];
}
}
Regards!
Does the custom UIView class have its own touch handling code? If not, a simple solution is to set the allowableMovement property of the UILongPressGestureRecognizer to CGFLOAT_MAX, or some big number, and use the gesture update callbacks to drag your custom view around. You can get the displacement using the - (CGPoint)locationInView:(UIView *)view method on the superview, and compare its position to when the recognizer began.
There are two solutions in my mind.
For animating uiview, please wrote a new class which is inherited from the UIView class and implement the touch delegates instead of writing the Gustures to handle animation(if the touch delegates are not triggering in the current class).
2.I have successfully removed the UILongPressGestureRecognizer after triggered it once.
Please refer the below code .ask me if you have any queries
Steps I have Done
I have added a UIView as "myView" to my main-view when main-view loads.
I have given the Tag to the myView (you can give 1,2,3…etc) to differentiate the tapped view from the main-view subviews.
Assigned the UILongPressGestureRecognizer gesture to myView and assigned target as "moveMe" method.
When user Pressed the myView long, the "moveMe" method will trigger.
Then I iterated the mainView Subviews with the condition Tag == 1
I have removed the UILongPressGestureRecognizer from the subview.As we can know that Tagged 1 main-view subView is myView.
So the NSLog(#"gesture removed"); and NSLog(#"moveMe"); will log in console only at one time.
The NSLog(#"touchesBegan"); will trigger first instead of triggering the "moveMe" method.
Then NSLog(#"touchesBegan"); will trigger always after removed the gesture . "moveMe" method will not trigger ever.
Code
- (void)viewDidLoad {
//Adding to UIView to main view when application is loading.
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 80, 80)];
myView.backgroundColor = [UIColor viewFlipsideBackgroundColor];
myView.tag = 1; //adding a tag to identify it.
//Adding Long Press Gesture to the UIView.
UILongPressGestureRecognizer *myGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(moveMe:)];
[myView addGestureRecognizer:myGesture];
[myGesture release];
myGesture = nil;
[self.view addSubview:myView];
[myView release];
myView = nil;
[super viewDidLoad];
}
//Method to trigger when user pressed long on the added UIView.
-(void)moveMe:(id)sender
{
for (UIView *subViews in [self.view subviews])
{
if (subViews.tag == 1) {
[subViews removeGestureRecognizer:sender];
NSLog(#"gesture removed");
}
}
NSLog(#"moveMe");
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesBegan");
}
or please refer Disable gesture recognizer iOS

Hide/Show iPhone Camera Iris/Shutter animation

I am not able to Hide the iphone Camera shutter opening animation for my app.
I am using UIImagePickerController to access iphone camera and using my own overlay controllers.
Is there a way to remove the initial shutter(also known as Iris) animation as the camera starts.
Thank You
[EDIT]
For those who wants to know the way to change the camera iris animation.
The below function is called before the camera iris animation starts.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Here is were I make the camera preview fit the entire screen.
// This might violate the "don't change the view hierarchy"-rule.
// So I am not sure if it is valid for App Store commitment.
// However, the NSLogs are used to
// figure out which subview is the actual Camera Preview which turns out
// to be the PLPreviewView. (uncomment to se the printouts).
// Change it's size to fit the entire screen (and scale it accordingly
// to avoid distorted image
NSLog(#"WillShowViewController called...");
NSLog(#"VC:view:subviews\n %#\n\n", [[viewController view] subviews]);
NSLog(#"VC:view:PLCameraView:subviews\n %#\n\n", [[[[viewController view] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLPreviewView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLCropOverLay:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 1] subviews]);
NSLog(#"VC:view:PLCameraView:UIImageView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 2] subviews]);
}
In the above function you can go through each layer by using the normal NSMuatableArray syntax like objectAtIndex
hope this might help you.
Regards,
Ankur
Using this answer as a starting point, I've finally solved this problem:
NOTE: This is obviously not 3.3.1-compliant.
Listen for the UINavigationControllerDidShowViewControllerNotification on your UIImagePickerController, and the PLCameraViewIrisAnimationDidEndNotification globally.
Traverse the view hierarchy (starting at the main UIWindow) looking for the PLCameraView. Save the index of the view against the main UIWindow, as you'll need it later.
Remove the PLCameraView from its superView. If desired, insert your own view at global index 0.
When the iris animation is finished, remove your view and re-add the PLCameraView at its original index.
Came across a similar: I wanted to have the shutter appear when I take the picture triggered by a button in a self.cameraOverlayView of a UIImagePickerController. Arrived to this page, did some extra research and came to this solution.
Synopsis:
#interface MyController : UIImagePickerController
...
- (id) init {
...
self.cameraOverlayView = _my_overlay_;
self.showsCameraControls = NO;
...
}
...
- (void) onMyShutterButton {
[self takePicture];
// You want the shutter animation to happen now.
// .. but it does not.
}
Solution:
// Some constants for the iris view and selector
NSString* kIrisViewClassName = #"PLCameraIrisAnimationView";
SEL kIrisSelector = NSSelectorFromString(#"animateIrisOpen");
#implementation MyController {
...
UIView* iris_;
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Find the iris view in the siblings of your overlay view
for (UIView* view in self.cameraOverlayView.superview.subviews) {
if ([kIrisViewClassName isEqualToString:[[view class] description]]) {
// It will be hidden by 'self.showsCameraControls = NO'.
view.hidden = false;
// Extra precautions - as this is undocumented.
if ([view respondsToSelector:kIrisSelector]) {
iris_ = view;
}
break;
}
}
}
- (void) animateIrisOpen {
if (iris_) {
[iris_ performSelector:kIrisSelector];
}
}
...
- (void) onMyShutterButton {
[self takePicture];
[self animateIrisOpen]; // Voila - the shutter happens
}
I've messed around with this a bit, but sending various combinations of the view lifecycle methods to the image picker. (viewWillAppear, viewDidAppear, etc.) But I don't remember which ones ended up working.
Sorry for replying getting back so late. I found out the solution for that well I played around with the view hierarchy of the cameraView and added my own layer at the top of everything. The animation took place there and once the shutter was open the top most layer was removed. If someone need any further help with the code please let me know, I will provide with the exact steps and syntax.
-Ankur
joshwa's answer completely hides the entire camera view for the duration of the iris animation. For my purposes, I needed the camera view visible, just without the iris animation. I was able to accomplish this with a little tweaking of his method. As others have noted, this may or may not be allowed on the app store since we're messing with the view hierarchy as well as listening for undocumented notifications.
3 ivars are needed:
UIImagePickerController *imagePickerController;
UIView *plCameraIrisAnimationView; // view that animates the opening/closing of the iris
UIImageView *cameraIrisImageView; // static image of the closed iris
Hide the closed iris image and remove the animation view. I tried simply hiding the animation view as well, but the animation was still visible:
- (void)receivedNavigationControllerDidShowViewControllerNotification:(NSNotification *)notification {
UIView *view = imagePickerController.view;
[plCameraIrisAnimationView release];
plCameraIrisAnimationView = nil;
cameraIrisImageView = nil;
while (view.subviews.count && (view = [view.subviews objectAtIndex:0])) {
if ([[[view class] description] isEqualToString:#"PLCameraView"]) {
for (UIView *subview in view.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
cameraIrisImageView = (UIImageView *)subview;
}
else if ([[[subview class] description] isEqualToString:#"PLCropOverlay"]) {
for (UIView *subsubview in subview.subviews) {
if ([[[subsubview class] description] isEqualToString:#"PLCameraIrisAnimationView"]) {
plCameraIrisAnimationView = [subsubview retain];
}
}
}
}
}
}
cameraIrisImageView.hidden = YES;
[plCameraIrisAnimationView removeFromSuperview];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UINavigationControllerDidShowViewControllerNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedPLCameraViewIrisAnimationDidEndNotification:) name:#"PLCameraViewIrisAnimationDidEndNotification" object:nil];
}
When the animation is over, unhide the iris image and re-add the animation view:
- (void)receivedPLCameraViewIrisAnimationDidEndNotification:(NSNotification *)notification {
cameraIrisImageView.hidden = NO;
UIView *view = imagePickerController.view;
while (view.subviews.count && (view = [view.subviews objectAtIndex:0])) {
if ([[[view class] description] isEqualToString:#"PLCameraView"]) {
for (UIView *subview in view.subviews) {
if ([[[subview class] description] isEqualToString:#"PLCropOverlay"]) {
[subview insertSubview:plCameraIrisAnimationView atIndex:1];
[plCameraIrisAnimationView release];
plCameraIrisAnimationView = nil;
break;
}
}
}
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"PLCameraViewIrisAnimationDidEndNotification" object:nil];
}
The below function is called before the camera iris animation starts.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Here is were I make the camera preview fit the entire screen.
// This might violate the "don't change the view hierarchy"-rule.
// So I am not sure if it is valid for App Store commitment.
// However, the NSLogs are used to
// figure out which subview is the actual Camera Preview which turns out
// to be the PLPreviewView. (uncomment to se the printouts).
// Change it's size to fit the entire screen (and scale it accordingly
// to avoid distorted image
NSLog(#"WillShowViewController called...");
NSLog(#"VC:view:subviews\n %#\n\n", [[viewController view] subviews]);
NSLog(#"VC:view:PLCameraView:subviews\n %#\n\n", [[[[viewController view] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLPreviewView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 0] subviews]);
NSLog(#"VC:view:PLCameraView:PLCropOverLay:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 1] subviews]);
NSLog(#"VC:view:PLCameraView:UIImageView:subviews\n %#\n\n", [[[[[[viewController view] subviews] objectAtIndex: 0] subviews] objectAtIndex: 2] subviews]);
}
In the above function you can go through each layer by using the normal NSMuatableArray syntax like objectAtIndex
hope this might help you.
Regards,
Ankur
To expound on Catalin's answer, (which was great btw), I found if you change the method "animateIrisOpen" slightly, the presentation is a fraction better... but noticeable.
- (void) animateIrisOpen {
if (iris_) {
iris_.hidden = NO;
[iris_ performSelector:kIrisSelector];
}
}