after some years I tried again to work with XCode to write some little apps for iOS.
My MainViewController contains these lines in viewdidload:
UIStoryboard* overviewStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *overviewController = [overviewStoryboard instantiateViewControllerWithIdentifier:#"Overview"];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:overviewController];
...
[self addChildViewController:nav];
[self.view addSubview:nav.view];
[nav didMoveToParentViewController:self];
the Controller behind the Overview contains the whole gesture recognition in view did load:
the property
#property (nonatomic, strong) UISwipeGestureRecognizer *swipeGestureUpDown;
viewdidload:
self.tableView.dataSource = self;
self.tableView.delegate = self;
// gesture recognizer top
self.swipeGestureUpDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipedScreen)];
self.swipeGestureUpDown.numberOfTouchesRequired = 1;
self.swipeGestureUpDown.direction = (UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown);
[self.view addGestureRecognizer:self.swipeGestureUpDown];
and swipedScreen only an nslog:
- (void)swipedScreen:(UISwipeGestureRecognizer*)gesture
{
NSLog(#"somewhere");
}
THE overviewcontroller contains a tableView with custom cells.
The maincontroller passes this overviewcontroller as rootcontroller to a navigation, which should be slideUp if you swipeUp, and slideIn if you swipeDown. The maincontroller is calling the navigationcontroller with rootcontroller as you've seen above.
Nothing happens, no gesture is recognized, and in some tries it crashes with this message
unrecognized selector sent to instance
does somebody now what to do?
Answer to the question came up in the comments. Just consolidating it here.
There were a few issues.
First:
self.swipeGestureUpDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipedScreen)];
#selector(swipedScreen) is missing : at end of swipedScreen which makes it unrecognizable as the definition of the function is - (void)swipedScreen:(UISwipeGestureRecognizer*)gesture
Second:
self.swipeGestureUpDown.direction = (UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown);
Having single gesture recognizer for two directions of swipe does not work. For details see this. You will need to have a dedicated gesture recognizer for each direction.
Third:
Most important of all was trying to add Up and Down direction swipes on UITableView which won't work as long as scrolling is enabled in UITableView as it has its own default actions to handle these swipes which prevents it from being handled manually. But if you have very limited content in the table and don't need scrolling, you can set scrollEnabled to false which will make UITableView stop using the gestures and forward the gestures higher up the responder chain. Refer scrollEnabled description here. (UITableView inherits from UIScrollView.)
Related
I am fairly new at programming in objective c and am trying to implement swipe gestures to swipe between view controllers on an app I am creating in xcode. I'm trying to make it so when I swipe left, it switches to another view controller that I have named "SecondViewController". I have created the outlet and action for my gesture in my .h file, and in my .m file I have added the following code:
- (IBAction)swipeLeft:(id)sender {
ViewController *SecondViewController = [[ViewController alloc] init];
[self presentViewController:SecondViewController animated:YES
completion:nil];
Whenever I run the app, nothing happens when I swipe. Is there something that I have not yet done that I need to do to make this work?
There are basically four Swipe Gesture is available:
UISwipeGestureRecognizerDirectionRight
UISwipeGestureRecognizerDirectionLeft
UISwipeGestureRecognizerDirectionUp
UISwipeGestureRecognizerDirectionDown
You can use any of it as per your requirement. To adding any of above gesture, you can alloc Gesture and then add it to your particular view. So as soon as you swipe detected, it will call relevant method.
For Example for Right and Left gesture:
UISwipeGestureRecognizer *gestureRecognizerRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeHandlerRight:)];
[gestureRecognizerRight setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.view addGestureRecognizer:gestureRecognizerRight];
UISwipeGestureRecognizer *gestureRecognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeHandlerLeft:)];
[gestureRecognizerLeft setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.view addGestureRecognizer:gestureRecognizerLeft];
-(void)swipeHandlerRight:(id)sender
{
}
-(void)swipeHandlerLeft:(id)sender
{
}
I'm trying to launch a popover from one of several UITableViewRowActions in a custom UITableviewCell. It appears that there are no off the shelf delegate methods available to do this in a straightforward way, but my searches turned up the following approaches to the problem:
How to get a reference to button from UITableViewRowAction?
How to correctly start a popover segue from a custom uitableviewcell using the storyboard
How do I implement the UITapGestureRecognizer into my application
Segue from editActionsForRowAtIndexPath
IOS: verify if a point is inside a rect
How to detect a tap gesture in subviews
While each of these was helpful with some aspect of a workaround, none was comprehensive. However, using some guidance from each, I eventually arrived at this code:
else if ([[segue identifier] isEqualToString:#"AccountPopSegue"])
{
UITapGestureRecognizer *tapGestureRecognizer;
CGPoint point = [tapGestureRecognizer locationInView:_thisCustomCell.contentView];
UIView *tappedView = [_thisCustomCell hitTest:point withEvent:nil];
UIViewController *controller = segue.destinationViewController;
controller.popoverPresentationController.delegate = self;
controller.preferredContentSize = CGSizeMake(320, 186);
UIPopoverPresentationController *thisPPC = controller.popoverPresentationController;
thisNavController = (UINavigationController *)segue.destinationViewController;
AccountChangeVC *acCVC = (AccountChangeVC *)thisNavController.topViewController;
acCVC.delegate = self;
thisPPC.sourceRect = tappedView.bounds;
thisPPC.sourceView = tappedView.superview;
}
A tap on the the "Acct" action produces the following behavior, shown for three row cases:
So it appears that I'm close to achieving my desired presentation, but not quite there.
Can anyone suggest changes that will make the popover point directly at the launching UITableViewRowAction button?
in VideoPlayer.h:
#interface VideoPlayer : NSObject <UIGestureRecognizerDelegate>
#property (nonatomic, retain) UIView *playerView;
in VideoPlayer.m custom init method:
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userDidTapScreen:)];
tgr.delegate = self; // tried with and without
tgr.cancelsTouchesInView = NO; // tried with and without
[self.playerView addGestureRecognizer:tgr];
....
- (void)userDidTapScreen:(UITapGestureRecognizer *)tap {
NSLog(#"user tapped");
}
Because this object is part of an SDK, we don't have a view controller. But even if I set the delegate in the View Controller of a project using the SDK, I still have no luck. If I had another view as a subView to self.playerView, the tap gesture works on that view, even if I'm still adding gesture to self.playerView. I have removed all subviews to make sure nothing is blocking and when I do that, still no luck. I know that typically view controllers handle this and if I put all the tap gesture code in the view controllers, it works, but if I only set the view controller as the delegate and that's the only gesture code on the view controller, it doesn't work.
When added to a project's view controller:
VideoPlayer *player = [[VideoPlayer alloc] initWithFrame:CGRectMake(10, 100, 320, 200)];
[self.view addSubview:player.playerView];
UITapGestureRecognizer * recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
recognizer.delegate = self;
[player.playerView addGestureRecognizer:recognizer];
This isn't ideal for our SDK. I think we could tell anyone using it to set delegate in their view controller, but that doesn't even work when that's the only line in the view controller.
Any help would be greatly appreciated. I've done a lot of tap gestures both in code and through IB and never this problem.
I am facing problem with Accessibility read order issue.
I have a UIViewController in that 3 UIViewControllers added as childViewControllers.
NavigationController is added to the MainViewController.
When I turn on the accessibility, VO start reads from the childviewcontroller subviews and then moving to NavigationController. After reading the navigation bar Vo will not move down.
- (void)viewDidLoad
{
[super viewDidLoad];
self.suppressCart = YES;
[self setupNavigationItems];
// Set up the embedded navigation controller for the delivery/payment/review
// subviews
self.stepController = [[UINavigationController alloc] init];
self.stepController.delegate = self;
self.stepController.navigationBarHidden = YES;
// Add it to this view controller as a child
// Note: do not call begin/end appearance transitions
[self addChildViewController:self.stepController];
[self.view addSubview:self.stepController.view];
self.stepController.view.frame = CGRectOffsetAndShrink(self.view.bounds, 0, TargetBreadcrumbButtonHeight);
}
self.stepController is used to push the view controllers with in the MainViewController.
Did any one face this issue before. Need help to resolve this.
Is there any way to make VO reads every element in Infinite Loop??
Thanks,
Rakesh
My UIRefreshController is doing something odd.
When I pull-down refresh, the tableView headers are displaced.
If I pull-down it looks fine, but if I scroll down the table while the refresher is still working, the headers are offset by the height of the refresh control while the UITableCells are fine and scroll behind the header.
I want to avoid creating a tableViewController, and so I am doing the following in viewDidLoad:
_refreshControl = [[UIRefreshControl alloc] init];
[_refreshControl addTarget:self action:#selector(refresh) forControlEvents:UIControlEventValueChanged];
[_tableView addSubview:_refreshControl];
I have a lot of tables in different view controllers that require this functionality. Is there any way I can avoid making a UITableViewController for each one?
Thanks a ton!
This could be an issue due to the fact that you are adding _refreshControl as a subview which is not supposed to be done. However you can create a UITableViewController object add it as the child view controller of your current viewcontroller class.
For eg:-
UITableViewController *tableViewController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
[self addChildViewController:tableViewController];
tableViewController.refreshControl = [[UIRefreshControl alloc] init];
[tableViewController.refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
tableViewController.tableView.frame = CGRectMake(...);//set the frame here
[self.view addSubview:tableViewController.tableView];
a quick fix to this is to go like this
Objective-C
//header
#property UITableViewController *tableController;
//.m (right at the beginning of viewDidLoad for example)
self.tableController = [[UITableViewController alloc] init];
[self addChildViewController:self.tableController];
self.tableController.tableView = self.tableView;
...
//then create the refresh control and assign it to the UITableViewController
self.tableController.refreshControl = refreshControl;
Swift 2.1
//Create an instance of a UITableViewController. This will host your UITableView.
private let tableController = UITableViewController()
//Add tableController as a childViewController and set its tableView property to your UITableView.
self.addChildViewController(self.tableController)
self.tableController.tableView = self.tableView
self.refreshControl.addTarget(self, action: "refreshData:", forControlEvents: .ValueChanged)
self.tableController.refreshControl = self.refreshControl
this helps if you have your table hooked up to an IBOutlet and have other things linked into the storyboard you dont feel like messing with.
UIRefreshControl's aren't meant to be subviews, they're meant to (literally) be the table's refresh control. UITableViewController has an outlet specifically for them (again, literally called refreshControl) that you should be using. As a subview of the table, you may be causing the table to assume it's a cell, rather than just a subview, which forces a recalculation around it. There will be cases where you do get lucky and the control may set itself in the right place, but this is, again, the result of undefined behavior.
UITableViewController is not meant to be a limiting class, and it certainly should not keep you from implementing "multiple table views" (which sound context-specific enough that they'd warrant a new view controller presented anyhow). If you are worried about having to write boilerplate for each class, write an abstract superclass controller for every table view you want to implement, and subclass it as necessary.
#available(iOS 10.0, *)
tableView.refreshControl = refreshControl
Try this way to add push view controller.
Create a table view controller and add it as the sub view of existing view controller. Then assign your table view and refresh controllers to tableview controller's properties.
UITableViewController *newTableViewController = [[UITableViewController alloc] init];
newTableViewControler.tableView = <yourTableView>;
<yourRefreshController> = [[UIRefreshControl alloc] init];
[<yourRefreshController> addTarget:self
action:#selector(refreshTableView:)
forControlEvents:UIControlEventValueChanged];
newTableViewController.refreshControl = _chatListRefreshControl;
[self addChildViewController:newTableViewController];