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.


Monday, 26 June 2017

Protocol in Swift

There are three main pillar of swift that provides facility to write your code in a way which will decrease the size of code and also improve make your code scalable , easy to read and maintainable.

These pillar are:
1) Value types
2) Functional programming
3) Protocol oriented programming

In swift for value types we use struct and enum. Value types copied when they are assigned, passed as argument to function. We won’t dive in deep for value type and functional programming here. In this blog I am going to discuss about protocol oriented programming. 


     protocol  TestProtocol{
        func  sayHello()
       
    }

    Like classes, we can inherit protocol also.
   
    struct Person: TestProtocol{
         
      //implement TestProtocol here
      func sayHello(){
       print(“Hi”)
        }

    }

   Protocol Extension:                                

 It’s not necessary to always implement a protocol . You can provide the default definition of a protocol in Protocol extension. You can also provide your implementation , in this case you will override the default implementation.

    extension TestProtocol{
    
  func sayHello(){
       print(“default implementation ”)
        }

    }

   If a protocol extension provide the definition of a function , then it’s not necessary to implement a protocol on the type which conforms it.

    struct Area:TestProtocol{

    }

    Area().sayHello


In protocol we declare the type and tell it what to do but not how to do. A protocol is like a coach , he tells the player what to do . Protocol is like interface in JAVA. Let’s understand protocol with an example:

Let’s say you have page in which you have two UILabel and a UIButton and main UIView of  your screen. Now  each UILabel and UIButton have a series of animation. 

So What approach will you take here:

1) You can directly write your animation code in main view controller in place where you want, this could be worst approach. What if you want other views to have same animation? So here comes the second approach.

2) In this approach , you can subclass your UILabel and UIButton to have animation and in future if you want other UILabel and UIButton to have same animation , you just replace their class. 

3) As you will say , swift provide even a better approach than subclassing , As we know UILabel and UIButton has the same parent UIView. So you can create an extension to UIView and write animation there. This is good approach, but this will open this for all views in your application. So here comes the Protocol .

In Protocol you just declare what to do and then each control which wants to have animation must have to implement this.

Protocol  Fadable{
}

extension Fadable where  Self:UIView{
   func fade{
      //do your animation here
    }
 }

So any UIComponents that conforms to Fadable protocol would have the fade() method with it. Here  where  Self:UIView used to indicate  that the protocol  should be only conformed  to UIView or view which are inherited from UIView.


class MyLable:UILabel, Fadable{
  //write your code
}


Reference:

Sunday, 18 June 2017

Background color of status bar

UINavigationBar includes status bar which is of 20 points in height of UINavigationBar. Thus the actual default height of UINavigationBar is 44 point. 
When we change the background color of UINavigationBar, it includes the background color of status bar also. Thus by setting the background color of UINavigationBar with 

        UINavigationBar.appearance().barTintColor = UIColor.Red

will set the background color of navigation bar as well as status bar to red.

Thus to set the different background color of status bar other than navigation bar's tint color, you can use these line of code in your application at appropriate place:

        //change appearance of status bar
        
        UINavigationBar.appearance().clipsToBounds = true
        //get the status bar
        let statusBar: UIView? = UIApplication.shared.value(forKey: "statusBar") as? UIView
        //set background color
        statusBar?.backgroundColor = UIColor.white

Sunday, 11 June 2017

UIImagePickerController in Swift

In iOS app development UIImagePickerController is used to access the picture either from the camera or photos app. It's very easy to use UIImagePickerController. But what if we want to access image picker more than once in an iOS app. Here we don't want redundant code .

In swift it's very easy to write code which can be used all over the application. Yes the rescue is the extension. We can create an extension of UIViewController which can be called from every view controller where we want to present the image picker.

In iOS 10, first of all we have to declare the usage of camera and photos app in info.plist.

Then create an extension of UIViewController to present image picker:

 func imagePickerControllerWith(delegate:(UIImagePickerControllerDelegate & UINavigationControllerDelegate)?){
        let actionSheet =  UIAlertController(title: "YakYapp", message: "", preferredStyle: .actionSheet)
        
        let camera  = UIAlertAction(title: "Camera", style: .default) { (cameraAction) in
            
            let mediaType = AVMediaTypeVideo
            
            let authorizationStatus =  AVCaptureDevice.authorizationStatus(forMediaType: mediaType)
            
            if authorizationStatus == .authorized{
                self.prsentImagePickerWith(option: "Camera",delegate: delegate)
                
            }else if authorizationStatus == .notDetermined{
                AVCaptureDevice.requestAccess(forMediaType: mediaType, completionHandler: { (newStatus) in
                    if newStatus {
                        let authorizationStatus1 =  AVCaptureDevice.authorizationStatus(forMediaType: mediaType)
                        if authorizationStatus1 == .authorized{
                            self.prsentImagePickerWith(option: "Camera",delegate: delegate)
                        }
                        
                    }else{
                        
                    }
                })
            }else{
                
                let message = "It seems access for camera is denied for Spirosure. To make it work, Go to Setting -> Privacy -> Camera and enable the access for the app"
                self.showAlertWith(message: message, title: "", handler: nil)
            }
        }
        
        let gallery  = UIAlertAction(title: "Photo Album", style: .default) { (galleryActn) in
            
            let status = PHPhotoLibrary.authorizationStatus()
            
            switch status{
                
            case .authorized:
                self.prsentImagePickerWith(option: "PhotoAlbum",delegate: delegate)
            case .notDetermined:
                PHPhotoLibrary.requestAuthorization({ (newStatus) in
                    if newStatus == PHAuthorizationStatus.authorized{
                        self.prsentImagePickerWith(option: "PhotoAlbum",delegate: delegate)
                        
                    }else{
                        
                    }
                })
            default:
                self.showAlertWith(message: "The access is not granted to use photo library. Go to Setting app to change the access for the app.", title: "", handler: nil)
                
            }
        }
        
        let cancel  = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        
        actionSheet.addAction(camera)
        actionSheet.addAction(gallery)
        actionSheet.addAction(cancel)
        self.present(actionSheet, animated: true, completion: nil)
        
    }
    
   private func prsentImagePickerWith(option:String,delegate:(UIImagePickerControllerDelegate & UINavigationControllerDelegate)?){
        let uiimagePicker = UIImagePickerController.init()
        uiimagePicker.delegate = delegate
        
        if option == "Camera" && UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera){
            uiimagePicker.sourceType = .camera
        }else {
            uiimagePicker.sourceType = .photoLibrary
        }
        
        DispatchQueue.main.async {
            self.present(uiimagePicker, animated: true, completion: nil)
        }
        
    } 

Here we created an action sheet to let user select the source from which he/she will pick the image and then we check based on choice of user, whether this app has access to that source or not and if allowed then present the image picker.

To use in your view controller:

A) First set the viewcontroller  to implement the delegate for UIImagePickerControllerDelegate and UINavigationControllerDelegate

B) Then call method of extension to present an image picker from your view controller as:
        
      self.imagePickerControllerWith(delegate: self)

Sunday, 4 June 2017

TextColor and backgroundColor Properties of UISearchBar

UISearchBar search text color

If we want to set the search text color in UISearchBar, we can do this either programmatically or in interface builder.

In order to change the text color in UISearchBar, we have to access the UITextField inside the UISearchBar. We can do this by using valueForKey("searchField")

var textFieldInsideSearchBar = yourSearchbar.valueForKey("searchField") as? UITextField

textFieldInsideSearchBar?.textColor = yourcolor

To set the text color of UISearchBar in interface builder,  go to in identity inspector- > User Defined Runtime Attributes -> in Key Path add searchField.textColor  and in Type write Color and in value set color.

In swift we can also create an extension for UISearchBar

public extension UISearchBar {

   public func setTextColor(color: UIColor) {
       let svs = subviews.flatMap { $0.subviews }
       guard let tf = (svs.filter { $0 is UITextField }).first as? UITextField else { return }
       tf.textColor = color
   }
}

UISearchBar background color

If you want to set the background color of UISearchBar,  you can change it in your ViewController and don't want anywhere else to effect then use

for view in searchBar.subviews {
           for subview in view.subviews {
               if subview .isKindOfClass(UITextField) {
                   let textField: UITextField = subview as! UITextField
                   textField.backgroundColor = UIColor.redColor()
               }
           }
    }

But if you want it to be change in whole app and targeting the iOS 9.0 or later then should be using appearanceWhenContainedInInstancesOfClasses like

UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).backgroundColor = UIColor.redColor()

Sunday, 28 May 2017

Uses of Block in Objective C

Block is same as the c function.The basic idea of a block is to treat a small piece of code as if it were a value. The piece of code can then be passed as a parameter in messages or assigned to a variable. 

With the help of block it's very easy  to write code which is simple , easy to debug, readable and maintainable. So let's have a look at the syntax and see how it works:


^{NSLog(@"This is a block"); }


A block is the only object that begins its life in stack, rather than heap memory.A very effective use of a block literal is to deal with a callback. 

Creating a block variable:

int  (^sum)(int, int) = ^(int a , int b){
 return a+b;
}

This  is a simple block definition . It takes two parameters  of type int and return one int parameter.
To call this block as:

int c = sum(3,5);
NSLog(@"sum is %d",c);

When a block is created, it will capture, or close around, the values of those variables that the code has referred to and that are in the same lexical scope of the block. Essentially, a snapshot is taken of these values. These values are preserved in the memory allocated for the block and cannot later be changed. It is said that these variables are "captured by value".
To change the this behavior(to use the latest values of the variable), we can declare these variable as 
__block storage specifier.

__block int z =5;

Block as method parameter: We can also use block as method parameter to use call back. For example:

-(void)validateString:(NSString *)str onCompletion:(void(^)(bool isValidate))completion{
          
 if(str.length ==0){
    completion(NO); //call block
}else{
    completion(YES);
}
}

Now call this method as 

[self validateString:@"demoiOS" onCompletion:^(bool isValidate){
    
if(isValidate){
 //str is valid, handle it
}else{
  // str is not valid, handle it here
}       
   
}];