Search This Blog

Friday, June 9, 2017

React Native Troubleshooting


Situation 1. New (Just Created) React Native Project now working

You decided to start develop React Native Application and after installation React Native library you create new project and try to run it on iOS Simulator.

npm install -g react-native-cli

react-native init AwesomeProject

cd AwesomeProject

react-native run-ios

And You getting Error

Lets see what versions are used. React native Version 0.45. For knowing version of React Native that used in project open file package.json in project folder. I found this issue June 10, 2017. 

Dependencies in package.json file
"dependencies": {
 "react": "16.0.0-alpha.12",
 "react-native": "0.45.0"
}

Error screens




Solution

And what we have to do here?

  1. Stop process and close all terminal windows (close react packager window)
  2. Open terminal window again
  3. Go to project folder
  4. Run command 
    1. npm run start -- --reset-cache
  5. Open project in xcode and run it
  6. It should be work

XCode Compilation Success




Run successfully and without errors on the simulator




Sources


Situation 2. React Native Project now working after adding npm library

For example, you want to add new cool library to your project. For me this library is
react-native-svg

You install the library 
npm install react-native-svg --save

After you link the library
react-native link react-native-svg

Then you try to run your project from XCode 
(after invoking) 
npm run start -- --reset-cache

And finally you get an error


Let's see more detailed what error it is

Solution


So, this error happen because of problems with tvOS targets. Because  don't need tvOS target in project I just remove them.

Targets before removing tvOS



Target after removing tvOS


Next, I remove library named libRNSVG-tvOS.a for tvOS from iOS Target Linked Frameworks and Libraries. And try to run application.





Try to run project and everything goes successfully


App now is successfully running


Sources



Situation 3. React Native Project got error "Cannot find module 'jest-haste-map'" when you try to update version of some library

For example, you try to update or install library for Facebook integration (react-native-fbsdk) 
react-native install react-native-fbsdk

and you get the error
module.js:472
    throw err;
    ^

Error: Cannot find module 'jest-haste-map'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/alexeydanilov/Documents/work/ipoint/badlibs-react-native/node_modules/react-native/packager/src/node-haste/DependencyGraph.js:16:22)
    at Module._compile (module.js:571:32)
    at loader (/Users/alexeydanilov/Documents/work/ipoint/badlibs-react-native/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/alexeydanilov/Documents/work/ipoint/badlibs-react-native/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)

Solution

Solution is simple. You just need to remove react-native and install it again.
npm uninstall react-native

npm install react-native

After that you can try to install library again and it should be work fine.
npm-install info Linking react-native-fbsdk android dependency 
rnpm-install info Android module react-native-fbsdk has been successfully linked 
rnpm-install info Linking react-native-fbsdk ios dependency 
rnpm-install info iOS module react-native-fbsdk has been successfully linked 
rnpm-install info Module react-native-fbsdk has been successfully installed & linked 

Tuesday, March 14, 2017

Create custom UITextField and custom clear button for it


Goals


  1. Create custom UITextField
    1. It should be transparent
    2. It should have border
    3. It should have rounded corners
    4. Rounded corners and border width should be setting via Xcode Interface Builder (IBInspectable / IBDesignable)
  2. Create custom clear button for custom UITextField
    1. Use Extensions for creating custom clear button
    2. Use Google Material Design Icon as image for button
    3. Set for button image custom color
    4. Make button always visible even if textfield is not in focus
    5. Set for button padding from right side of textfield
  3. Make textfield not editable but still available for touches
    1. Do not show keyboard
    2. Add default parameter values
    3. Clear button should be available for tap
    4. Fill textfield by clicking on special button
    5. Send Local Notification when custom clear button is tapped
  4. Use completely different approach for the same goal - Create custom clear button without adding Right View in UITextField

Implementation


Custom TextField

import UIKit
import UIKit

@IBDesignable
class CustomTextField: UITextField {
    
    @IBInspectable
    var borderWidth: CGFloat {
        get {
            return self.layer.borderWidth
        }
        set {
            self.layer.borderWidth = newValue
        }
    }
    
    @IBInspectable
    var borderColor: UIColor? {
        get {
            return UIColor(cgColor: self.layer.borderColor!)
        }
        set {
            self.layer.borderColor = newValue?.cgColor
        }
    }
    
    @IBInspectable
    var cornerRadius: CGFloat {
        set {
            self.layer.cornerRadius = newValue
        }
        get {
            return self.layer.cornerRadius
        }
    }

}






Add Custom Clear Button with Extensions


import Foundation
import UIKit

extension UITextField {
    
    func clearButtonWithImage(_ image: UIImage) {
        let clearButton = UIButton()
        clearButton.setImage(image, for: .normal)
        clearButton.frame = CGRect(x: 0, y: 0, width: 15, height: 15)
        clearButton.contentMode = .scaleAspectFit
        clearButton.addTarget(self, action: #selector(self.clear(sender:)), for: .touchUpInside)
        self.rightView = clearButton
        self.rightViewMode = .always
    }
    
    func clear(sender: AnyObject) {
        self.text = ""
    }
    
}

override func viewDidLoad() {
        super.viewDidLoad()
        
        let clearImage = UIImage(named: "ic_close_white_48pt")!
        self.firstWordTextField.clearButtonWithImage(clearImage)
}





Moving Clear Button

override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
        var rightViewRect = super.rightViewRect(forBounds: bounds)
        rightViewRect.origin.x -= 10;
        return rightViewRect
}

import UIKit
import UIKit

@IBDesignable
class CustomTextField: UITextField {
    
    @IBInspectable
    var borderWidth: CGFloat {
        get {
            return self.layer.borderWidth
        }
        set {
            self.layer.borderWidth = newValue
        }
    }
    
    @IBInspectable
    var borderColor: UIColor? {
        get {
            return UIColor(cgColor: self.layer.borderColor!)
        }
        set {
            self.layer.borderColor = newValue?.cgColor
        }
    }
    
    @IBInspectable
    var cornerRadius: CGFloat {
        set {
            self.layer.cornerRadius = newValue
        }
        get {
            return self.layer.cornerRadius
        }
    }
    
    override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
        var rightViewRect = super.rightViewRect(forBounds: bounds)
        rightViewRect.origin.x -= 10;
        return rightViewRect
    }

}





Add Color to Clear Button

import Foundation
import UIKit

extension UITextField {
    
    func clearButtonWithImage(_ image: UIImage,
                              _ imageColor: UIColor = UIColor.white,
                              _ isAlwaysVisible: Bool = true) {
        let clearButton = UIButton()
        clearButton.tintColor = imageColor
        let coloredImage = image.withRenderingMode(.alwaysTemplate)
        clearButton.setImage(coloredImage, for: .normal)
        clearButton.frame = CGRect(x: 0, y: 0, width: 15, height: 15)
        clearButton.contentMode = .scaleAspectFit
        clearButton.addTarget(self, action: #selector(self.clear(sender:)), for: .touchUpInside)
        self.rightView = clearButton
        self.rightViewMode = isAlwaysVisible ? .always : .never
    }
    
    func clear(sender: AnyObject) {
        self.text = ""
    }
    
}


Create two clear buttons with default color and with custom color

override func viewDidLoad() {
        super.viewDidLoad()
        
        let clearImage = UIImage(named: "ic_close_white_48pt")!
        
        self.firstWordTextField.clearButtonWithImage(clearImage)
        self.secondWordTextField.clearButtonWithImage(clearImage, UIColor.red)
}




Send Local Notification when tapped on clear button

import Foundation
import UIKit

extension UITextField {
    
    func clearButtonWithImage(_ image: UIImage,
                              _ imageColor: UIColor = UIColor.white,
                              _ isAlwaysVisible: Bool = true) {
        let clearButton = UIButton()
        clearButton.tintColor = imageColor
        let coloredImage = image.withRenderingMode(.alwaysTemplate)
        clearButton.setImage(coloredImage, for: .normal)
        clearButton.frame = CGRect(x: 0, y: 0, width: 15, height: 15)
        clearButton.contentMode = .scaleAspectFit
        clearButton.addTarget(self, action: #selector(self.clear(sender:)), for: .touchUpInside)
        self.rightView = clearButton
        self.rightViewMode = isAlwaysVisible ? .always : .never
    }
    
    func clear(sender: AnyObject) {
        self.text = ""
        
        NotificationCenter.default.post(
            name: Notification.Name("TextFieldCleared"), object: nil, userInfo: nil)
    }
    
}

override func viewDidLoad() {
        super.viewDidLoad()
        
        let clearImage = UIImage(named: "ic_close_white_48pt")!
        
        self.firstWordTextField.clearButtonWithImage(clearImage)
        self.secondWordTextField.clearButtonWithImage(clearImage, UIColor.red)
        
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(ViewController.clearSelection),
                                               name: Notification.Name("TextFieldCleared"),
                                               object: nil)
}




Full Code of ViewController

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var firstWordTextField: CustomTextField!
    
    @IBOutlet weak var secondWordTextField: CustomTextField!
    
    @IBOutlet weak var firstButton: UIButton!
    
    @IBOutlet weak var secondButton: UIButton!
    
    var isFirstSelected: Bool = false
    
    var isSecondSelected: Bool = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let clearImage = UIImage(named: "ic_close_white_48pt")!
        
        self.firstWordTextField.clearButtonWithImage(clearImage)
        self.secondWordTextField.clearButtonWithImage(clearImage, UIColor.red)
        
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(ViewController.clearSelection),
                                               name: Notification.Name("TextFieldCleared"),
                                               object: nil)
    }
    
    @IBAction func firstButtonTapped(_ sender: Any) {
        if !self.isFirstSelected {
            self.firstWordTextField.text = "Fill First TextField"
            self.setFirstButtonSelected(selected: !self.firstButton.isSelected)
        }
    }
    
    @IBAction func secondButtonTapped(_ sender: Any) {
        if !self.isSecondSelected {
            self.secondWordTextField.text = "A long time ago"
            self.setSecondButtonSelected(selected: !self.secondButton.isSelected)
        }
    }
    
    
    func clearSelection() {
        if self.isFirstSelected {
            if let text = self.firstWordTextField.text {
                if text.isEmpty {
                    self.setFirstButtonSelected(selected: false)
                }
            }
        }
        
        if self.isSecondSelected {
            if let text = self.secondWordTextField.text {
                if text.isEmpty {
                    self.setSecondButtonSelected(selected: false)
                }
            }
        }
    }
    
    func setFirstButtonSelected(selected: Bool) {
        self.isFirstSelected = selected
        self.firstButton.isSelected = selected
    }
    
    func setSecondButtonSelected(selected: Bool) {
        self.isSecondSelected = selected
        self.secondButton.isSelected = selected
    }

}


Sources




Monday, March 6, 2017

Firebase create user with email, password, display name and photo url


Problem

In Firebase you can create user account with email and password. But what if you want to set user displayName and photo?  For that purpose after creating user with email and password you can use FIRUserProfileChangeRequest.

Algorithm


  1. Create new user with email and password with completion handler with method FIRAuth.auth()?.createUser
  2. In success of completion handler use method of user  user.profileChangeRequest() and set user display name changeRequest.displayName and commit changes changeRequest.commitChanges

Source Code

     /* 
     1. Create new user account with email and password.
     2. Update create account and set user display name.
     */
    func registerNewUser(email: String,
                  password: String,
                  displayName: String,
                  successHandler: ((_ uid:String) -> Void)?,
                  errorHandler: ((_ errorString: String) -> Void)?) {
        FIRAuth.auth()?.createUser(
            withEmail: email,
            password: password,
            completion: { (user, error) in
                if let error = error {
                    if let errorHandler = errorHandler {
                        errorHandler(error.localizedDescription)
                    }
                } else if let user = user {
                    let changeRequest = user.profileChangeRequest()
                    changeRequest.displayName = displayName
                    changeRequest.commitChanges(completion: { error in
                        if let error = error {
                            if let errorHandler = errorHandler {
                                errorHandler(error.localizedDescription)
                            }
                        } else if let successHandler = successHandler {
                            successHandler(user.uid)
                        }
                    })
                }
        })
    }

Link to Firebase Documentation



Sunday, March 5, 2017

UIImageView Content Modes

For new people in ios development slightly unclear how work content mode for UIImage View. What is the difference between scale modes for UIImageView?
There are three main scales modes
  • scale to fill (FILL image in UIIMageView frame - image will be changed)
  • scale aspect fit (scale image to FULLY FIT in UIIMageView frame - image will be the same but may change size)
  • scale aspect fill (scale image until smallest side fits UIImageView frame - some part of image may be clipped)
I wrote a demo program to show how this modes work.

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var switcher: UISwitch!
    
    @IBOutlet weak var imageView: UIImageView!
    
    @IBOutlet weak var segmentedControl: UISegmentedControl!
    
    @IBAction func segmentSelected(_ sender: Any) {
        let index = self.segmentedControl.selectedSegmentIndex
        switch index {
        case 0:
            self.imageView.contentMode = .scaleToFill
            break
        case 1:
            self.imageView.contentMode = .scaleAspectFit
            break
        case 2:
            self.imageView.contentMode = .scaleAspectFill
            break
        default:
            self.imageView.contentMode = .scaleAspectFit
            break
        }
    }
    
    @IBAction func switcherChanged(_ sender: Any) {
        self.imageView.clipsToBounds = self.switcher.isOn
    }
    
}

Original Image




Scale To Fill



Scale Aspect Fit




Scale Aspect Fill (NO Clip To Bounds)



Scale Aspect Fill (Clip To Bounds)