Silver challenge


#1

Has anyone figured out how to change the background color? I tried overriding viewWillAppear but can’t find the methods.


#2

Here are some hints:

  1. The ConversionViewController inherits a property, i.e. a variable, named view from the UIViewController class.

If you go back to p. 46, 48, you will see examples that use the view variable to change properties of the view. The view variable is mentioned again in this chapter on p. 82.

  1. You are asked to change the background color of the view.

One way to figure out how to do that is: When you are in Xcode, look up at the menu bar–at the very top of your computer screen. Click on:

In the search bar, type in:

Then click on the first item in the search results. That will take you to the UIView docs. Read the preamble at the top.

Next, search the UIView page for “background color”: Hit Command+F for Find, and type in: background color. Use the arrows on the far right of the search bar to advance to the next match. You’ll find this:

[code]Configuring a View’s Visual Appearance
backgroundColor
Property
The view’s background color.

Declaration
SWIFT
@NSCopying var backgroundColor: UIColor?
[/code]

The last line is a little confusing: there’s something similar to @IBOutlet at the start: @NSCopying. Those @Variables so far in our experience have been indicators for Xcode, which allow us to make links to or from our storyboard, so let’s ignore it. That leaves:

That seems a little easier to understand. It looks like you have to assign something that is of type UIColor to a view’s backgroundColor property. In the docs, click on the name: UIColor?. On the page for the UIColor docs, read the preamble. Then start looking down the page for methods. If you don’t find anything that you can understand, skip down to the section:

The title is a little confusing, but the gist of it is: there are some default colors you can use. Note that ‘+’ before a function name means it’s a class function, which means you use the class name to call the function. A ‘-’ sign before a function means it’s an instance function, which means you use an instance of the class to call the method.

Another option: In Xcode, type:

and look at the the different methods and properties that the autocompletion menu presents you.

A third option: In Xcode type:

then Option+click on view, and read the popu menu. Follow the links in the popup window, and see where that leads you.

Next, you need to figure out how to get the current time, and then the current hour: 1-24. Check out some Swift Date and Calendar tutorials.

A couple of things to note:

  1. When you override a method, you are interrupting the flow of function calls up the view hierarchy. As a result, you may need to call super in the functions that you override so that the flow continues up the hierarchy. I’m not sure whether we need to call super in viewWillAppear().

  2. When you assign a dark background to the view, you will no longer be able to see some of the text. If you were wondering why all the text in the ConversionViewController’s view wasn’t orange, I’m sure that was by design for this exercise. Now you have to figure out how to change the black text to white, so that it is visible on a dark background.

  3. If you create a color in a playground, the playground actually will show you the color. Neat. Click on the circle to the far right of the line that creates the color.


#3

Thanks i am new to programming and get stuck sometimes.


#4

I don’t know how you do it! This stuff is hard for experienced programmers. The Date stuff is pretty confusing in most languages. I figured something out, so if you need help, post up.


#5

I find that Mr Google is a strong friend to find clues (e.g. Swift how to get time). Once you know where to start looking in the documentation (e.g. NSDate for date/time) then things start to fall into place.


#6

Hi Guys,
Here is my solutions along with the thinking. I realised that the one of the most important accessory for the book is not mentioned , which is pen and paper. So step wise here is the solution
1. Decide a time for which you want to apply dark mode (here I chose apple timings of 6PM to 6AM)
2. Get the hour in NSDate and calendar forma (search google on how to get date in the swift or this is what I read globalnerdy.com/2015/01/26/h … t-part-one) , I am afraid I am still unable to follow apple documentation, they sometimes appear Greek and Latin (though i am learning programming Greek and Latin :slight_smile:
3. Since time is in 24 hours so I used if condition along with or
4. Then use the hint as given in the challenge (viewWillAppear(_:slight_smile: which will be used along side the override func. I used that along with view.backgroundcolor (this is what the first item popped after I put the dot and then here I could read the documentation.
And here is the code

[code]override func viewWillAppear(animated: Bool) {
let hour = NSCalendar.currentCalendar().component(NSCalendarUnit.Hour, fromDate: NSDate())
if (hour > 18 || hour < 6) {
view.backgroundColor = UIColor.lightGrayColor()

    } else {
        view.backgroundColor = UIColor.whiteColor()
    }

}

[/code]
So thinking through the challenge is more important. but my code has couple of glitches, if my default background colour is not white then how to allow view to set to that (there is no .defalutcolor() property) also I am struggling with the second part “(If that is not enough excitement in your life, you can change the background color each time the view controller is viewed.)”
I know it will involve looping and i need to use a view counter but how to determine how many times a screen has been viewed and then one solution is for even view use default and for odd use some other (like red or orange) but then if I want to change the view each time as mentioned how to do that. I hope this helps


#7

Great answer NikhiliOS!

You helped me out with the use of NSCalendar. I was trying to work out how to get the hour from an NSDate directly!

For the change of colour each time the view appears, I simply generated a random colour each time viewWillAppear(_:slight_smile: is called.

        let color = UIColor(red: CGFloat(Double(arc4random_uniform(101)) / 100.0),
                            green: CGFloat(Double(arc4random_uniform(101)) / 100.0),
                            blue: CGFloat(Double(arc4random_uniform(101)) / 100.0),
                            alpha: 1.0)

There may be a better way of generating a random double between 0.0 and 1.0 if anyone can recommend one?


#8

My solution based on german winter hours :slight_smile:

override func viewWillAppear(animated: Bool) {
        
        let date = NSDate()
        let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
        let components = calendar?.components(.Hour, fromDate: date)
        let currentHour = components!.hour
        
        let lightColor = UIColor.init(red:0.961,  green:0.957,  blue:0.945, alpha:1)
        let darkColor = UIColor.init(red:0.184,  green:0.184,  blue:0.188, alpha:1)
        
        switch currentHour {
            
        case 0...6, 20...23:
            view.backgroundColor = darkColor
        break
            
        default:
            view.backgroundColor = lightColor
            
        }
        
    }

#9

Here are some hints:

  1. The ConversionViewController inherits a property, i.e. a variable, named view from the UIViewController class.

If you go back to p. 46, 48, you will see examples that use the view variable to change properties of the view. The view variable is mentioned again in this chapter on p. 82.

  1. You are asked to change the background color of the view.

[/quote]

Wow, so much time and thought went into that entire answer post.

Thank you. Maybe you should be writing a book :ugeek:


#10

I opted for the “not enough excitement” method, so I just toggled the background color.

In ConversionViewController.swift:

var backColor:Bool=false override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) // also seems to work without this if backColor==true { backColor=false view!.backgroundColor=UIColor.yellowColor() } else { backColor=true view!.backgroundColor=UIColor.greenColor() } }


#11

Good use of the NSCalendar guys. It’s much more concise IMO. I used NSDate in my solution because I didn’t know about NSCalendar.

override func viewWillAppear(animated: Bool) {
        var hour: Int?
        let currentDate = NSDate()
        let dateFormatter = NSDateFormatter()
        
        dateFormatter.locale = NSLocale.currentLocale()
        dateFormatter.dateFormat = "HH"
        
        hour = Int(dateFormatter.stringFromDate(currentDate))
        
        if hour < 7 || hour > 19 {
            view.backgroundColor = UIColor.blackColor()
        } else {
            view.backgroundColor = UIColor.cyanColor()
        }
    }

#12

Here’s my solution. Didn’t fine tune the color, but it works. I set the time to 8:00 PM for “evening”.

[code]override func viewWillAppear(animated: Bool) {
let cal = NSCalendar.currentCalendar()
let eve: NSDate! = cal.dateBySettingHour(20, minute: 0, second: 0, ofDate: NSDate(), options: [])
let now = NSDate()

if eve.compare(now) == .OrderedAscending {
self.view.backgroundColor = UIColor.grayColor()
}
}[/code]


#13

If your dark mode sets the background to black with UIColor.blackColor(), the placeholder text for the “value” text field and “is really” are not readable. Here is how I fixed this issue:

  1. Create an outlet for the “is really” label and change its color property:
    isReallyLabel.textColor = UIColor.whiteColor()

  2. Use NSAttributedString to change the placeholder color of the “value” text field:
    let placeholder = NSAttributedString(string: "value", attributes: [NSForegroundColorAttributeName: UIColor.grayColor()]) textField.attributedPlaceholder = placeholder

Hope that helps! :sunglasses:


#14

The font, textColor, and textAlignment properties, among others, affect the appearance of the text field’s string. Modifying these properties applies the specified characteristic to the entire string. To specify more granular formatting, specify the text field’s text using an NSAttributedString object.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextField_Class/

An NSAttributedString object manages character strings and associated sets of attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string.

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSAttributedString_Class/index.html#//apple_ref/occ/cl/NSAttributedString


#15

Eh, I got messing around with this and came up with this, also got some of the ideas from up above, so thanks.

override func viewWillAppear(animated: Bool) {
    let darkColor = UIColor.init(red:0.784,  green:0.784,  blue:0.788, alpha:1)
    let lightColor = UIColor.init(red:0.961,  green:0.957,  blue:0.945, alpha:1)
    
    if setBackgroundForEvening(getTheHour()) {
        view.backgroundColor = darkColor
    } else {
        view.backgroundColor = lightColor
    }
    
}

func getTheHour() -> Int {
    let date = NSDate()
    let calendar = NSCalendar.currentCalendar()
    let components = calendar.components([.Hour, .Minute], fromDate: date)
    return components.hour
}

func setBackgroundForEvening(hourToCheck: Int) -> Bool {
    
    switch hourToCheck {
    case 0...6:
        return true
    case 7...18:
        return false
    case 19...23:
        return true
    default: return false
    }
}

#16

I don’t think the name of your setBackground...() function makes any sense. A setter function that returns a Bool seems odd. I think you should change the name to something like isDarkOutside().

And, you don’t need to extract the .Minute from the date–you don’t use it.


#17

Hi alyDouglas,

regarding the white color:
you can initialise a UIColor with Floats for the RGB and Alpha Channel. The floats should have a value between 0.0 and 1.0
So you could use this approach and simply use the colcor picker we used to define the color in Interface builder. It was r:245 g:244 b:241 and alpha would be 1.0
So the code would be as follows

 } else {
    view.backgroundColor = UIColor(colorLiteralRed: 245/255, green: 244/255, blue: 241/255, alpha: 1.0)
 }

greets bd


#18

I decided to combine the two parts of the challenge into a combination solution. So for the random color, I set that during daylight and for the evening or dark mode I set that to dark grey.

So here’s my code:

override func viewWillAppear(animated: Bool) {
    let currentDate = NSDate()
    let currentCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
    let currentComponents = currentCalendar?.components(.Hour, fromDate: currentDate)
    let currentHour = currentComponents!.hour
    
    let backgroundUIColor = UIColor(red: CGFloat(Double(arc4random_uniform(101)) / 100.0),
                            green: CGFloat(Double(arc4random_uniform(101)) / 100.0),
                            blue: CGFloat(Double(arc4random_uniform(101)) / 100.0),
                            alpha: 1.0)
    
    switch currentHour {
        case 0...6, 20...23:
            view.backgroundColor = UIColor.darkGrayColor()
            break
        default:
            view.backgroundColor = backgroundUIColor
    }
}

#19

Hi angelcaro,

Here is my solution, maybe not the best because I am a beginner but it works ! :wink:

`override func viewWillAppear(animated: Bool) {

    // Change view background color if evening is coming
    changeBackgroundColor()
    
    
}

func changeBackgroundColor()
{
    let dateJour = NSDate()
    let userCalendar = NSCalendar.currentCalendar()
    let unitFlags: NSCalendarUnit = [.Hour, .Day, .Month, .Year]
    let dtComponents = userCalendar.components(unitFlags, fromDate: dateJour)
    
    print(dtComponents.hour)
    
    var viewBackgroundColor: UIColor = UIColor.cyanColor()
    let actualHour = dtComponents.hour
    
    
    if 0...12 ~= actualHour {
        viewBackgroundColor = UIColor.darkGrayColor()
    }
    else if 13...17 ~= actualHour  {
        viewBackgroundColor = UIColor.cyanColor()
    }
    else {
        viewBackgroundColor = UIColor.blackColor()
    }
    
    self.view.backgroundColor = viewBackgroundColor
    
    
    
    
}

`


#20

Here’s mine (I went with the non-exciting version). Note I kept the original background color for the day color & chose a random darker gray for night viewing.

override func viewWillAppear(animated: Bool) {
    
    let calendar = NSCalendar.currentCalendar()
    let hour = calendar.component(.Hour, fromDate: NSDate())
    
    let dayColor = UIColor(red: 0xF5/255, green: 0xF4/255, blue: 0xF1/255, alpha: 1)
    let nightColor = UIColor(red: 0x4b/255, green: 0x54/255, blue: 0x57/255, alpha: 1)
    
    if hour >= 8 && hour <= 20 {
        self.view.backgroundColor = dayColor
    } else {
        self.view.backgroundColor = nightColor
    }
}