I work on an iOS application that implements a UITabBarController with 5 icons connected. The whole project is made via Storyboard. As I want to give the option for 4 themes to the user, which thing I do in a static tableView, I came across an issue.
When the user changes theme, the previously instantiated via the tabBar view controllers do not update to the theme change because they exist before the theme update. Can I somehow dismiss them and create new instances of the same view controller classes upon the didSelect method of the UITabBar delegate?
Am I approaching the issue correctly? Any help would be much appreciated!
Thanks you in advance for your help.
class MainTabController: UITabBarController
{
override func viewDidLoad()
{
super.viewDidLoad()
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem)
{
let theme = UserDefaults.standard.string(forKey: "selectedColor")
print(theme!)
for vc in self.viewControllers!
{
if (theme == "default")
{
vc.view.backgroundColor = UIColor(red: 0xF9 , green: 0xF7 , blue: 0xF7)
}else if (theme == "theme1")
{
vc.view.backgroundColor = UIColor(red: 0x1F , green: 0xFF, blue: 0xFF)
}else if (theme == "theme2")
{
vc.view.backgroundColor = UIColor(red: 0xE3 , green: 0xFD, blue: 0xFD)
}else if (theme == "theme3")
{
vc.view.backgroundColor = UIColor(red: 0x3E, green: 0xC1, blue: 0xD3)
}
}
}
}
example of implementing in each view controller:
override func viewDidLoad()
{
let theme = UserDefaults.standard.string(forKey: "selectedColor")
print(theme!)
if (theme == "default")
{
outerView.backgroundColor = UIColor(red: 0xF9 , green: 0xF7 , blue: 0xF7)
}else if (theme == "theme1")
{
outerView.backgroundColor = UIColor(red: 0x1F , green: 0xFF, blue: 0xFF)
}else if (theme == "theme2")
{
outerView.backgroundColor = UIColor(red: 0xE3 , green: 0xFD, blue: 0xFD)
}else if (theme == "theme3")
{
outerView.backgroundColor = UIColor(red: 0x3E, green: 0xC1, blue: 0xD3)
}
}
Inside didSelect you can access the tab VCs and change them as you like ( inside any VC in the tab )
for vc in self.tabBarController!.viewControllers! {
vc.view.backgroundColor = UIColor.red
// if you want to set a property
if let other = vc as? OtherViewController {
// change here
}
}
//
if you want this code inside the tabBar custom class
for vc in self.viewControllers! {
vc.view.backgroundColor = UIColor.red
// if you want to set a property
if let other = vc as? OtherViewController {
// change here
}
}
//
after your edit , you need to either create a protocol containing the outerView and conform to this protocol in every VC or cast to the VC and change it's property
Create custom UITabBarController class and in it's viewDidLoad add :
for vc in self.viewControllers! {
vc.view.backgroundColor = .....
}
Now link this custom class to the Storyboard's UITabBarController.
Update :
You are getting the value from UserDefaults incorrectly.
UserDefaults.standard.string(forKey: "selectedColor")
It should be :
UserDefaults.standard.object(forKey: "selectedColor")
The solution to my problem was really simple but only after many hours of searching!
I had to put all my code that is editing the view in viewDidAppear instead of viewDidLoad because viewDidLoad is running only on the first time in contrast with
viewDidAppear which is called every time the user presses this particular tab.
Thank you all for your fast answers!
Related
I’m using left side menu from jonkykong/SideMenu this framework. Here i need to change background view colour alpha value while open(means click on button) the side menu and when i close the side menu i need back the original background colour.
for that I have tried two methods:
Method 1):
func sidemenuOpenCloseColorChang(){
let menu = storyboard!.instantiateViewController(withIdentifier: "UISideMenuNavigationController") as! UISideMenuNavigationController
var set = SideMenuSettings()
set.statusBarEndAlpha = 0
set.presentationStyle = SideMenuPresentationStyle.menuSlideIn
set.presentationStyle.presentingEndAlpha = 0.5
set.menuWidth = min(view.frame.width, view.frame.height) * 0.90
//menu.sideMenuManager.addScreenEdgePanGesturesToPresent(toView: self.view)
menu.settings = set
//SideMenuManager.default.addScreenEdgePanGesturesToPresent(toView: view)
SideMenuManager.default.leftMenuNavigationController = menu
}
getting below error:
Use of unresolved identifier 'SideMenuSettings'
Use of unresolved identifier 'SideMenuPresentationStyle'
Value of type 'SideMenuManager' has no member 'leftMenuNavigationController'
Method 2): using UISideMenuNavigationControllerDelegate Metod
#IBAction func sideMenubtn(_ sender: Any) {
view?.backgroundColor = UIColor(white: 1, alpha: 0.9)
}
extension ProfileViewController : UISideMenuNavigationControllerDelegate {
private func sideMenuWillDisappear(menu: UISideMenuNavigationControllerDelegate, animated: Bool) {
//*do the color thing*
print("sidemenu disappear")
view?.backgroundColor = UIColor.white
}
Nothing worked for me, please help me in this code.
Thanks in advance
I am getting only these 3 options every time
while my whole code is working any help will be appreciated.
let selections = pdfView.currentSelection?.selectionsByLine()
guard (selections?.first?.pages.first) != nil else { return }
selections?.forEach({ selection in
let newAnnotation = PDFAnnotation(bounds: selection.bounds(for: pdfView.currentPage!) ,forType: PDFAnnotationSubtype.highlight ,withProperties: nil)
// Add additional properties to the annotation
newAnnotation.color = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
self.pdfView.currentPage?.displaysAnnotations = true
self.pdfView.currentPage?.addAnnotation(newAnnotation)
})
I'm struggling with this question as well, but cannot find any option to add it to PDFView in iOS.
In the end I stumbled on a general method of adding menu-items via the shared UIMenuController class.
let menuItem = UIMenuItem(title: "Highlight", action: #selector(HighLightHandler.highlightSelection(_:)))
UIMenuController.shared.menuItems = [menuItem]
And handle any the highlight:
#objc func highlightSelection(_ sender: UIMenuItem) {
//put your highlighting code here
}
When using a UISegmentedControl, I have a problem fitting all the labels, precisely in Japanese.
I did not notice the same issue with the other language I used at this point.
Here is my code:
interfaceChoice = UISegmentedControl(items: ["白黒モード", "緑赤青・モード"])
for i in 0..<interfaceChoice.subviews.count {
interfaceChoice.subviews[i].tintColor = localColor
for subSubView in interfaceChoice.subviews[i].subviews {
if subSubView is UILabel {
(subSubView as! UILabel).adjustsFontSizeToFitWidth = true
}
}
}
I would hope the line ..adjustsFontSizeToFitWidth.. would sort things out, but it does not work as one can see in the picture below.
Anyone has an idea as what I am doing wrong?
Storyboard example
This is how I did it.
In a story board, drag and drop a segmented control into the title area of the view controller.
Link the segmented control to an IBOutlet in the view controller.
This code
class ViewController: UIViewController {
#IBOutlet weak var interfaceChoice: UISegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
interfaceChoice.removeAllSegments()
interfaceChoice.insertSegment(withTitle: "白黒モード", at: 0, animated: false)
interfaceChoice.insertSegment(withTitle: "緑赤青・モード", at: 1, animated: false)
interfaceChoice.selectedSegmentIndex = 0
let font = UIFont.boldSystemFont(ofSize: 16)
interfaceChoice.setTitleTextAttributes([NSFontAttributeName: font], for: .normal)
interfaceChoice.tintColor = UIColor(red: 27/CGFloat(255), green: 77/CGFloat(255), blue: 102/CGFloat(255), alpha: 1.0)
}
}
Note: I won't pretend to know exactly why it's not behaving for you, but I hope this can help. If it is absolutely imperative to fix your exact situation, I think we might need more information.
Pure code example
This produces the same result as setting it up in the storyboard.
class ViewController: UIViewController {
var interfaceChoice: UISegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
interfaceChoice = UISegmentedControl(items: ["白黒モード", "緑赤青・モード"])
interfaceChoice.selectedSegmentIndex = 0
let font = UIFont.boldSystemFont(ofSize: 16)
interfaceChoice.setTitleTextAttributes([NSFontAttributeName: font], for: .normal)
interfaceChoice.tintColor = UIColor(red: 27/CGFloat(255), green: 77/CGFloat(255), blue: 102/CGFloat(255), alpha: 1.0)
self.navigationItem.titleView = interfaceChoice
}
}
I would like to know in which function e.g viewDidLoad etc.. would be the best approach to load custom view properties like image border heights, color, all appearance.
For example I add custom values like these in cellForRowAtIndexPath which I think is not best way to do it:
// corner radius
cell.feedImageView.layer.cornerRadius = 10
// border
cell.feedImageView.layer.borderWidth = 2.0
cell.feedImageView.layer.borderColor = UIColor.black.cgColor
cell.feedImageView.layer.masksToBounds = true
And these navigationBar appearance I load in viewDidLoad and i use it in many views:
navigationController?.navigationBar.barTintColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5)
self.navigationItem.leftBarButtonItem = nil
navigationController?.navigationBar.isTranslucent = true
let fontDictionary = [ NSForegroundColorAttributeName:UIColor.white ]
self.navigationController?.navigationBar.titleTextAttributes = fontDictionary
self.navigationController?.navigationBar.tintColor = UIColor(red: 0.184, green: 0.996, blue: 0.855, alpha: 1.00)
So the question again, where should I load appearance values? I ask it because right now I am in situation where my image border is loading before image etc..
There are so many functions like viewDidLoadAppearance(), ViewDidload(). I've read many questions where they ask what is difference between them but I still do not know where is best to load appearance.
You have basically 3 different options.
1) You could get or set those values in the viewDidAppear() func, after they have been completely instantiated.
2) You could get or set them in the vieDidLayoutSubviews() function and set a bool to check if your task has been called.
var didConfigureUI = false
func viewDidLayoutSubviews() {
if !didConfigureUI {
didConfigureUI = true
updateUI()
}
}
3) You could get or set them in the viewDidLoad using layoutIfNeeded():
override func viewDidLoad() {
super.viewDidLoad()
xy.view.layoutIfNeeded() // <- This will update your initial view frames
updateUI()
}
And your func to do whatever:
func updateUI() {
//f.e feedImageView.layer.masksToBounds = true
}
And to do it in your cellForRowAtIndexPath, you would do something like this, using the layoutIfNeeded() as well.
cellForRowAtIndexPath {
let cell = tableView.blahblahcell
updateUICell(cell.feedImageView)
}
func updateUICell(imageView: UIImageView) {
imageView.layoutIfNeeded()
imageView.layer.cornerRadius = 10
imageView.layer.borderWidth = 2.0
imageView.layer.borderColor = UIColor.black.cgColor
imageView.layer.masksToBounds = true
}
And to answer the last question about the lifecircle:
The circle is:
init
UIViewController awakeFromNib
loadView // your pictureImageView is loaded here
UIView awakeFromNib
UIViewController viewDidLoad
viewWillAppear
viewDidAppear // the properties of your pictureImageView are available here
class mainTabBarViewController: UITabBarController, UITabBarControllerDelegate {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
tabBarController?.delegate = self
self.moreNavigationController.topViewController.view.backgroundColor = UIColor(red: 25.0/255.0, green: 25.0/255.0, blue: 25.0/255.0, alpha: 1.0)
let view = self.moreNavigationController.topViewController.view as UITableView
for cell in view.visibleCells(){
let tableCell = cell as UITableViewCell
tableCell.backgroundColor = UIColor(red: 25.0/255.0, green: 25.0/255.0, blue: 25.0/255.0, alpha: 1.0)
tableCell.textLabel?.textColor = UIColor.whiteColor()
}
}
func tabBarController(tabBarController: UITabBarController, willBeginCustomizingViewControllers viewControllers: [AnyObject]) {
let editView = tabBarController.view.subviews[1] as UIView
editView.backgroundColor = UIColor.redColor()
}
}
Here is my current code. I got the code that's in the 'willBeginCustomizingViewControllers' from an old website (around 4-5 years old) and it worked then apparently but it's not doing anything now. I want to change the background of the "Edit" modal view within the moreNavigationController to the same colour as i have set to the table cells in the viewWillAppear. I've put red for now just to test. Any ideas?
I've done some research, but i cant seem to find anything. I'm not sure its even possible.
There is one more option, but its not so easy. You can call your fifth tab 'more', and place a collection view inside it to access all of the other tabs (just copy apple's 'more' tab, but just start from scratch on a new view controller.).