How to set initial focus to a button in a viewController from a UITabBarController? - uitabbarcontroller

I have a basic application with a UITabBarController which contains 2 UIViewControllers.
The first ViewController has a UIButton in it.
I'm trying to get the tabBar menu hidden and the button focused when the app launches.
I set the tabBar as hidden, and it does not show on launch as expected. Unfortunately, the button doesn't have the focus.
From what I understand from Apple doc, the "focus chain" engine will set focus on the first visible and focusable item in the window hierarchy.
Can anyone help me on this ?
Thank you.

Solution 1.
I think what you can do :
1.Subclass or Customize TabBarController and set
set first launch = true in viewdidload of tabController
> override weak var preferredFocusedView: UIView? { if
> (self.firstLaunch) {
> self.firstLaunch = false;
> return self.selectedViewController!.preferredFocusedView; } else {
> let view = super.preferredFocusedView
> return view; }
Hope it helps.It worked for me though
Your focus engine takes the rootView controller as TabBarController and then asks for preferred focus view which is returned as UITabBarItem we need to unfocus that subclassing the class and returning canBecomeFocus to NO.
if you want to change the focus of the element in the firtsViewController then you can overrirde func preferredFocusView and reutrn the view you want to be focussed else preferredFocusView
Solution 2. Just set the root View controller as the HomeViewController without the TabBarController and embed the TabBarController from the second page. This is because anyways you don't need to use TabBar on the first page why need to take care of its focus.
TabBar is set to hidden if you hide from the AppDelegate or the view which is loaded but it has the focus.

Related

Swiftui checking if UIHostingController is presented

I have 2 screens with which I am navigating between them. One screen is for clicking a button to navigate to the other screen and the other screen is for presenting some other information.
Screen one
I have the following piece of swift code since screen 2 uses third part library
let host = UIHostingController(rootView: AnyView(vc))
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let application = windowScene?.windows.first
ScanGuideContainer(title: self.viewModel.defaultLocalizer.stringForKey(key: ""), icon: icon,action: {
application?.rootViewController?.present(host, animated: true, completion: {
})
})
.environmentObject(viewModel)
This automatically launches a modal pop which then navigates to Screen2.
Screen 2
This screen has two options either to go back to the modal by pressing the back button or automatically go back once done processing some information which when it does so it returns a new value which then I can use to dismiss the host automatically since its a boolean value.
I can access the second screen viewController via
secondScreen?.viewController
How can i dismiss the modal from first screen when user presses back button of second screen?
What I tried
.onChange(of: self.ViewModel.dismissModal){ newvalue in
if(newvalue) {
host.dismiss(animated: true)
}
}
I set self.ViewModel.dismissModal value from second screen on but it does not work. please help

Hiding and showing button on pickerView selection

I am new to swift. I have a viewController
Initially the pickerView is hidden but it appears on clicking on textField then it hides again. I want the button hide upon pickeriew selection and then unhide after selection. This is how i am doing it.
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
pickerView.isHidden = false
return false
}
I can hide the backButton like backButton.isHidden = true but it won't show when the selection is done.
Just make visible the back button when picker value is selected and hide the pickerview
func pickerView(pickerView: UIPickerView!, didSelectRow row: Int,
inComponent component: Int)
{
backButton.isHidden = false
pickerView.isHidden = true
}
If you want to to show the picker view during textfield selection, then you need to add picker view as textfield's input view. You can refer this link also https://blog.apoorvmote.com/uipickerview-as-inputview-to-uitextfield-in-swift/

How to create Side Menu on right side in Swift 3.0?

I am a beginner and I wanted to create a side menu on the right side.
So far I have a UIButton on right top side of viewController, what I want is when I click that button I want to show/hide slide menu with say 3 items…
when I click each item it will go to the different view controller. In my project, i am showing slide menu in only one viewController using AMSlideMenu. Thanks in advance.
Anuj just follow the steps-
Create a SideMenuViewController which is sub class of UIViewController , using storyboard how it will look according to the requirement.
Add this SideMenuViewController and its view as a child view controller in parent view controller by UIButton click.
When you done, remove SideMenuViewController from parent View controller and remove its view from parent view.
Repeat 2 and 3 for all view controllers.
Updated code :
Declare in your view controller -
var sideMenuViewController = SideMenuViewController()
var isMenuOpened:Bool = false
In viewDidLoad
sideMenuViewController = storyboard!.instantiateViewController(withIdentifier: "SideMenuViewController") as! SideMenuViewController
sideMenuViewController.view.frame = UIScreen.main.bounds
In your button Clicked event -
func openAndCloseMenu(){
if(isMenuOpened){
isMenuOpened = false
sideMenuViewController.willMove(toParentViewController: nil)
sideMenuViewController.view.removeFromSuperview()
sideMenuViewController.removeFromParentViewController()
}
else{
isMenuOpened = true
self.addChildViewController(sideMenuViewController)
self.view.addSubview(sideMenuViewController.view)
sideMenuViewController.didMove(toParentViewController: self)
}
}
For Animation:
let transition = CATransition()
let withDuration = 0.5
transition.duration = withDuration
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromLeft
sideMenuViewController.view.layer.add(transition, forKey: kCATransition)
There is no built-in control in iOS for side-menu. However, you could use different open source libraries to achieve your goal.
Have a look at the following libraries:
https://github.com/John-Lluch/SWRevealViewController
The detailed tutorial for this library:
http://www.appcoda.com/ios-programming-sidebar-navigation-menu/
http://www.raywenderlich.com/32054/how-to-create-a-slide-out-navigation-like-facebook-and-path

SWRevealViewController button not work after clicking Back button from another ViewController in Swift

I use SWRevealViewController for my project. My problem is that I can click on the SWRevealView Toggle button at first time and that button does not work after I click on Back button from another view controller and back to that view. Here is the screenshot of my project.
I click on NavigationLeft button from Service View Controller at first and left menu shows up. After that, I click on "Imageview" from that view controller to go to next page.
When I reached to detailed next page, I click on "Back button" and it goes to Service view controller.
At that time , I click on RevealView Toggle button , it does not work. I got error fatal error: unexpectedly found nil while unwrapping an Optional value.
My codes from Service View Controllers are;
override func viewDidLoad() {
super.viewDidLoad()
if self.revealViewController() != nil {
debugPrint("Menu Click")
btnBack.target = self.revealViewController()
btnBack.action = #selector(SWRevealViewController.revealToggle(_:))
self.revealViewController().panGestureRecognizer()
}
else
{
debugPrint("nil")
btnBack.target = self.revealViewController()
btnBack.action = #selector(SWRevealViewController.revealToggle(_:))
// self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
self.revealViewController().panGestureRecognizer()
}
}
When the project runs first time, the code passes to "self.revealViewController() != nil" and I go to detailed view controller and click on Back button. At that time the code passes to " debugPrint("nil")" and it does not show up menu or work.
Codes from Detailed view controller are;
#IBAction func btnBack(_ sender: UIBarButtonItem) {
debugPrint("BtnBack")
self.dismiss(animated: true, completion:nil)
}
Is my code is something wrong or logic wrong ? I have been trying to solve this problem since one week. Please help me ..
On click event of image view in serviceViewController,
let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "Detail") as! DetailVc
self.navigationController?.pushViewController(detailVC, animated: true)
Attach a navigation controller to detail viewcontroller. No need for manual connection between service and detail.
Add a barbutton for goingback event.
self.navigationController?.popViewController(animated: true)
Also add self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer()) instead of ur code in the lastline of adding target for menubutton.
Check whether this works.

How can I trigger one UIViewController of the UITabBarController from another UIViewController?

I have a project that is a "tab-bar controller" app. The first button is essentially a Home screen. The second one displays a UITableView of content. The third button displays a different UITableView, etc.
From the first view (Home), I have a button on the page that is functionally equivalent to the second-button of the tab controller. It is an alternative path to get to that UITableView. I do not want to send a button press to the AppDelegate's UITabBarController.
The code in HomeViewController that I want is essentially this:
-(IBAction) touchInsideButton:(id)sender {
[self presentModalViewController: [appDelegate secondViewController] animated:YES];
}
or
-(IBAction) touchInsideButton:(id)sender {
AppDelegate *appDelegate = (AppDelegate*) [[UIApplication sharedApplication] delegate];
[appDelegate launchSecondViewController: self];
}
where, "launchSecondViewController" is (uncomment-out one of the two lines)
-(void) launchSecondViewController: (id) sender {
// [self.tabBarController presentModalViewController: secondViewController animated:YES];
// [self.tabBarController.navigationController pushViewController: secondViewController animated:YES];
}
Regardless, all three approaches give the same error:
2013-05-16 12:04:26.977 MyApp[55273:f803] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller .'
* First throw call stack:
The problem is that this instance of the second view controller, which you refer to as secondViewController, is already in the interface, as a child of the tab view controller. You cannot have it be there and also present or push it.
The way to manipulate a tab bar controller in code is to set is selectedViewController (or selected index). Try doing that instead.