navigationBar display deranged - ios

I create a subclass of UINavigationController, like this
#interface CustomNav : UINavigationController
#property(assign , nonatomic) BOOL canBack;
#end
#implementation CustomNav
- (void)viewDidLoad {
[super viewDidLoad];
self.canBack = YES;
// Do any additional setup after loading the view.
id target = self.interactivePopGestureRecognizer.delegate;
UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc]
initWithTarget:target action:#selector(handleNavigationTransition:)];
pan.delegate = self;
[self.view addGestureRecognizer:pan];
self.interactivePopGestureRecognizer.enabled = NO;
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
// NSLog(#"self.childViewControllers.count = %li",self.childViewControllers.count);
if (self.childViewControllers.count==1||!self.canBack) {
return NO;
}
return YES;
}
#end
but when i use it to push viewController , the navigationBar display deranged ,for example, it has A viewController, then it push another B viewController,but sometimes, it doesn't display the navigationItem of B , it just display the navigationItem of A , and then I push C to the CustomNav , it also display the navigationItem of A. i don't know why ,i found it seems the CustomNav display the navigationItem of B(or C) ,and then the navigationBar covered by the navigationItem of A . Could everyOne help me ? Thank you ever so much.

Related

IOS/Objective-C: Programatically Change Text of Title for Standard UITabBar item

When a user segues to a second VC from within a starting VC that is embedded in a UITabBarController, I change the title of the UITabbarItem with some code placed in the viewWillAppear method of the second view controller.
//Second VC, View WIll Appear
UITabBarItem *selectedItem = self.tabBarController.tabBar.selectedItem;
if (selectedItem) {
selectedItem.title = #"VoiceMail";
}
This works fine.
When the user returns to the starting view controller, I want to switch the title back.
I tried to do this by placing similar code in the view will appear method of the starting view controller.
Starting VC: ViewWIllAppear
UITabBarItem *selectedItem = self.tabBarController.tabBar.selectedItem;
if (selectedItem) {
selectedItem.title = #"Phone";
}
But it is having no effect, leaving the title as Voicemail.
WOuld appreciate any suggestions on how to change back to initial value.
Thanks for any suggestions.
Trying to change the "2nd" tab title by referencing .selectedItem in your "Starting VC" won't work, because at that point .selectedItem is StartingVC.
One approach would be to save a reference to the index of SecondVC... then, inside that VC, on viewWillDisappear you can reset its tab's title:
This is all in SecondVC:
#import "ChangeSecondViewController.h"
#interface ChangeSecondViewController ()
#property (assign, readwrite) NSInteger myTabIndex;
#end
#implementation ChangeSecondViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UITabBarItem *selectedItem = self.tabBarController.tabBar.selectedItem;
if (selectedItem) {
selectedItem.title = #"VoiceMail";
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
_myTabIndex = self.tabBarController.selectedIndex;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
UITabBarItem *myTabItem = [[self.tabBarController.tabBar items] objectAtIndex:_myTabIndex];
if (myTabItem) {
myTabItem.title = #"Phone";
}
}
#end

Enable back back swipe gesture when using custom navigation controller

I've got a custom navigation controller declared as below. My problem is that once I implement this, the back swipe gesture to go back to previous stack (interactivepopgesturerecognizer) is not working. How can I enable it back? I've got a lot of view controller in my app. Thank You.
#import "NavController.h"
#interface NavController ()
{
BOOL shouldIgnorePushingViewControllers;
}
#end
#implementation NavController
-(instancetype)init {
self = [super init];
self.delegate=self;
return self;
}
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (!shouldIgnorePushingViewControllers)
{
[super pushViewController:viewController animated:animated];
}
shouldIgnorePushingViewControllers = YES;
}
- (void)didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
shouldIgnorePushingViewControllers = NO;
}
#end
Try to enable property
self.interactivePopGestureRecognizer.enabled = YES;
to init method

Implement SWRevealViewController on only one UITabBarItem

I implement SWRevealViewController with UITabbarController via storyboard.
I want to display SWRevealViewController in first UITabBarItem only, in other UITabBarItem i don't want to open SWRevealViewController, that done completely.
But problem is position of UITabBar is not change like viewcontroller while SWRevealViewController is appear.
Please help me.
Storyboard structure
I solve the problem by change position of UITabbar manually using SWRevealViewController delegate method.
Put this code in MenuViewController.
MenuViewController.m
- (void) viewDidLoad {
[super viewDidLoad];
UITabBarController *tbc = (UITabBarController *)[[[[UIApplication sharedApplication]delegate]window]rootViewController];
self.tabBar = tbc.tabBar;
_tabBar.frame = CGRectMake(self.revealViewController.rearViewRevealWidth, _tabBar.frame.origin.y, _tabBar.frame.size.width, _tabBar.frame.size.height);
self.revealViewController.delegate = self;
}
- (void) revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position {
if (position == FrontViewPositionRight) {
_tabBar.frame = CGRectMake(self.revealViewController.rearViewRevealWidth, _tabBar.frame.origin.y, _tabBar.frame.size.width, _tabBar.frame.size.height);
}
else {
_tabBar.frame = CGRectMake(0, _tabBar.frame.origin.y, _tabBar.frame.size.width, _tabBar.frame.size.height);
}
}
- (void)revealController:(SWRevealViewController *)revealController panGestureMovedToLocation:(CGFloat)location progress:(CGFloat)progress overProgress:(CGFloat)overProgress {
_tabBar.frame = CGRectMake(self.revealViewController.rearViewRevealWidth * progress, _tabBar.frame.origin.y, _tabBar.frame.size.width, _tabBar.frame.size.height);
}

UISearchController searchBar don't disappear when push viewcontroller

I'm using a UISearchController inside ma UIViewcontroller that contains a UITableView, I do this in viewDidLoad:
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.delegate = self;
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.delegate = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.definesPresentationContext = NO;
when I push a button in the navbar i do this:
self.tableView.contentOffset = CGPointMake(0, 0 - self.tableView.contentInset.top);
self.tableView.tableHeaderView = self.searchController.searchBar;
[self.searchController.searchBar becomeFirstResponder];
all works fine, but when I push a UIViewController from a row in the UITableView results the UISearchBar stay there and display also on the content of the other view, how can i dismiss when I push a view and present when I go back to see the result of the UITableView?
thanks
EDIT:
this is the code of the method didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
DetailListController *detailList = [[DetailListController alloc] init];
[self.navigationController pushViewController:detailList animated:YES];
}
Put this code in your viewDidLoad:
self.definesPresentationContext = YES;
You need to call this when you come back from DetailListController to your view controller (encapsulating in main thread for safety):
dispatch_async(dispatch_get_main_queue(), ^{
self.searchController.active = NO;
});
You can also call this in viewWillDisappear: of your current view controller.
Try this standard way suggested by apple:
Declare the properties:
#interface APLMainTableViewController () <UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating>
#property (nonatomic, strong) UISearchController *searchController;
// our secondary search results table view
#property (nonatomic, strong) APLResultsTableController *resultsTableController;
// for state restoration
#property BOOL searchControllerWasActive;
#property BOOL searchControllerSearchFieldWasFirstResponder;
#end
- (void)viewDidLoad {
[super viewDidLoad];
_resultsTableController = [[APLResultsTableController alloc] init];
_searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsTableController];
self.searchController.searchResultsUpdater = self;
[self.searchController.searchBar sizeToFit];
self.tableView.tableHeaderView = self.searchController.searchBar;
// we want to be the delegate for our filtered table so didSelectRowAtIndexPath is called for both tables
self.resultsTableController.tableView.delegate = self;
self.searchController.delegate = self;
self.searchController.dimsBackgroundDuringPresentation = NO; // default is YES
self.searchController.searchBar.delegate = self; // so we can monitor text changes + others
// Search is now just presenting a view controller. As such, normal view controller
// presentation semantics apply. Namely that presentation will walk up the view controller
// hierarchy until it finds the root view controller or one that defines a presentation context.
//
self.definesPresentationContext = YES; // know where you want UISearchController to be displayed
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// restore the searchController's active state
if (self.searchControllerWasActive) {
self.searchController.active = self.searchControllerWasActive;
_searchControllerWasActive = NO;
if (self.searchControllerSearchFieldWasFirstResponder) {
[self.searchController.searchBar becomeFirstResponder];
_searchControllerSearchFieldWasFirstResponder = NO;
}
}
}
#pragma mark - UISearchBarDelegate
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
#pragma mark - UISearchControllerDelegate
// Called after the search controller's search bar has agreed to begin editing or when
// 'active' is set to YES.
// If you choose not to present the controller yourself or do not implement this method,
// a default presentation is performed on your behalf.
//
// Implement this method if the default presentation is not adequate for your purposes.
//
- (void)presentSearchController:(UISearchController *)searchController {
}
- (void)willPresentSearchController:(UISearchController *)searchController {
// do something before the search controller is presented
}
- (void)didPresentSearchController:(UISearchController *)searchController {
// do something after the search controller is presented
}
- (void)willDismissSearchController:(UISearchController *)searchController {
// do something before the search controller is dismissed
}
- (void)didDismissSearchController:(UISearchController *)searchController {
// do something after the search controller is dismissed
}
and here comes the interesting part: Use the below code to restore the status when you comeback from the detail view
#pragma mark - UIStateRestoration
// we restore several items for state restoration:
// 1) Search controller's active state,
// 2) search text,
// 3) first responder
NSString *const ViewControllerTitleKey = #"ViewControllerTitleKey";
NSString *const SearchControllerIsActiveKey = #"SearchControllerIsActiveKey";
NSString *const SearchBarTextKey = #"SearchBarTextKey";
NSString *const SearchBarIsFirstResponderKey = #"SearchBarIsFirstResponderKey";
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
[super encodeRestorableStateWithCoder:coder];
// encode the view state so it can be restored later
// encode the title
[coder encodeObject:self.title forKey:ViewControllerTitleKey];
UISearchController *searchController = self.searchController;
// encode the search controller's active state
BOOL searchDisplayControllerIsActive = searchController.isActive;
[coder encodeBool:searchDisplayControllerIsActive forKey:SearchControllerIsActiveKey];
// encode the first responser status
if (searchDisplayControllerIsActive) {
[coder encodeBool:[searchController.searchBar isFirstResponder] forKey:SearchBarIsFirstResponderKey];
}
// encode the search bar text
[coder encodeObject:searchController.searchBar.text forKey:SearchBarTextKey];
}
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
// restore the title
self.title = [coder decodeObjectForKey:ViewControllerTitleKey];
// restore the active state:
// we can't make the searchController active here since it's not part of the view
// hierarchy yet, instead we do it in viewWillAppear
//
_searchControllerWasActive = [coder decodeBoolForKey:SearchControllerIsActiveKey];
// restore the first responder status:
// we can't make the searchController first responder here since it's not part of the view
// hierarchy yet, instead we do it in viewWillAppear
//
_searchControllerSearchFieldWasFirstResponder = [coder decodeBoolForKey:SearchBarIsFirstResponderKey];
// restore the text in the search field
self.searchController.searchBar.text = [coder decodeObjectForKey:SearchBarTextKey];
}
#end
After trying to deal with the same problem for a few days, realized that the proper way of doing this is to have a navigation controller that contains everything in the search hierarchy
like this :
Navigation 1 (no nav bar)
(.... tab bar, anything else ...)
Navigation 2 (has nav bar, this nav bar is replaced by the search bar
Table controller
when you push details controller, you push it into navigation 1, showing its navigation bar at the same time.
This leaves search stack untouched and ready to work when you hit "back" on the detail page

Using UIPageControl to navigate btween ViewControllers

I have
#property (weak, nonatomic) IBOutlet UIPageControl *pageCountControl;
Here is my code.
Inside viewDidLoad
// I set the number of pages to 5.
self.pageCountControl.numberOfPages = 5;
// the main view will be the home page so I set it to the index 0
self.pageCountControl.currentPage = 0;
// Then I think that I have to dd the UIPageControl as subview to the current view.
[self.view addSubview:_pageCountControl];
[self.pageCountControl addTarget:self action:#selector(pageTurn:) forControlEvents:UIControlEventValueChanged];
}
// here is my question. I have a method that will be calling when the user moved through the pages. Do I have to create that page like the following code?
-(void)pageTurn:(UIPageControl *) page
{
int c = page.currentPage;
if(c==0)
{
// here
MainViewController *mainViewController = [self.childViewControllers objectAtIndex:self.pageCountControl.currentPage];
}
// and here
else if(c==1)
{
MainViewController *mainViewController =[self.childViewControllers objectAtIndex:c];
SecondViewController *secondViewController = [self.childViewControllers objectAtIndex:self.pageCountControl.currentPage];
}
else if(c==2)
{
SecondViewController *secondViewController =[self.childViewControllers objectAtIndex:c];
ThirdViewController *thirdViewController = [self.childViewControllers objectAtIndex:self.pageCountControl.currentPage];
}
}
I found some tutorial about using UIPageControl for moving between images but there is no tutorial about using ViewControllers.
I am not sure if I am making it right?
Thank you.
Hind

Resources