Monday, 17 July 2017

Add gradient color as bar tint color in UINavigationBar

To set the background color of UINavigation bar , we set the barTintColor property of UINavigationBar.
        self.navigationController?.navigationBar.barTintColor = YOUR_COLOR

But what if you want to set the gradient color as tint color. For this we can take either create a CAGradientLayer with desired color and then render that layer in current graphics context and get the  image from the current context and set backgroundImage of the UINavigationBar.

Second we can draw a gradient image using core graphics without creating a CAGradientLayer and then set the backgroundImage of UINavigationBar.

Here we are going with second one, using core graphics. Swift provide us many functionalities to write reusable code so that we can use it anywhere in our application.


extension UIColor {
    convenience init(r: Float, g: Float, b: Float,alpha:Float) {
        self.init(colorLiteralRed: r/255, green: g/255, blue: b/255, alpha: alpha)
    }
}


extension UINavigationBar{
    
    func gradeintBarTintColor(with gradient:[UIColor]){
        var frameAndStatusBarSize = self.bounds
        frameAndStatusBarSize.size.height +=  20
        setBackgroundImage(UINavigationBar.gradient(size: frameAndStatusBarSize.size, color: gradient), for: .default)
    }
    
    static func gradient(size:CGSize,color:[UIColor]) -> UIImage?{
        //turn color into cgcolor
        let colors = color.map{$0.cgColor}
        
        //begin graphics context
        UIGraphicsBeginImageContextWithOptions(size, true, 0.0)
        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }
        
        // From now on, the context gets ended if any return happens
        defer {UIGraphicsEndImageContext()}
        
        //create core graphics context
        let locations:[CGFloat] = [0.0,1.0]
        guard let gredient = CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as NSArray as CFArray, locations: locations) else {
            return nil
        }
        //draw the gradient
        context.drawLinearGradient(gredient, start: CGPoint(x:0.0,y:0.0), end: CGPoint(x:0.0,y:size.height), options: [])
        
        // Generate the image (the defer takes care of closing the context)
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}




Usage:

Here I added gradient from top to bottom, you can change the implementation as per your requirements.
In your view controller, use like this:
        
//add gradeint color as bartint color
        
let colors = [UIColor(r: 73.0, g: 183.0, b: 229.0, alpha: 1.0),UIColor(r: 44.0, g: 154.0, b: 202.0, alpha: 1.0)]
        self.navigationController?.navigationBar.gradeintBarTintColor(with: colors)

Results:





References:

Sunday, 2 July 2017

Manage ViewController

Apple uses MVC pattern very efficiently for developing apps for iOS and OS X. Apple also expects from the developer who are going to develop apps to use MVC efficiently so that they can get the full advantage of MVC and delegate pattern.

Here I am assuming that you all know about what is MVC and how it works in real app development. So I am not going to dive in to elaborate about MVC. Here I will explain how to use it in iOS app development so that one can write readable, scalable and easy to maintain code.

A controller is designed  to take the the request from the view, parse the request and pass data to model for processing and get the result of processing from the model and return back it to view. But a common mistake we do in our development is that we forgot the model and handle all processing in controller results in a bulky controller. We also set the delegate of UITableView and and other UIComponents to controller, this also lead to increase the size of controller

The above described problem leads to unreadable, not able to maintain easily and even unable to understand for a new developer.

Thus how can we overcome from this problem in iOS app development and how can we make our controller skinny?

To get the answer to these question, you can follow these steps:
1) Try to set the delegate separate from the controller.
 For example, a delegate can be any class which can provide the implementation for the set of methods declared in protocol. Thus we can implement data source and delegate for the UITableView in a separate class and assign the reference  of object to datasource and delegate property of UITableView respectively in controller.

class MyDataSource: UITableViewDataSource, UITableViewDelegate{
    
       
        //implement required method here

}

Then in your view controller, first declare the property of type MyDataSource like this:

var myDataSource:MyDataSource!

and  set the datasource and delegate property of UITableVIew like this in viewDidLoad() method:

myDataSource = MyDataSource()
tableView.dataSource = myDataSource
tableView.delegate = myDataSource

2) Don't make any web service call in controller, try to make api call from your model class.
For example, if you want to send the data of user form(user profile details) to your server, for this you can create a user model class and make a method with completion handler (using closures) in model to call the web service to post the data.

3) Follow write less and produce more. Don't write redundant code, like you should avoid of writing the code which is to be used in more than one place.
In swift for this you can use extension, functional programming and protocol oriented programming to write more efficient code.