Create your own Custom Input View

While working on a client project, we had to build a custom input view which allowed users to respond back soon.

UIKit allows apps to customize input views for the system keyboard, it will allow customizing the selection for the input view

After figuring out input views, I found it is easy to create your own custom input view

Let’s get started how to build a sample app to use custom input view

Final_Sample

This is how it will look after building

Creating a custom input view

Let’s create a Custom Input view named Keyboard To get started, Create a new Xcode project or open an existing project. Select File\New\File choose View in User Interface Section name the File as Keyboard, it will create a new file as Keyboard.xib

Here we can use any UI element, we have to display list of message template, we will use collection view for that

  • Drag a Collection View to view give 4 constraint to its margin
  • Make a class for keyboard xib, File\New\File in iOS section choose Cocoa Touch and subclass as UIView name it as Keyboard.swift
  • Set the nibs file owner as Keyboard.swift, please take a note that we have to set File owner as our custom class Keyboard.swift not, and make sure that the custom class for the root view is blank

file_owner

  • Make a new collection view cell
  • In xib add a textview, set its editable false and add 4 constraint to view and take a reference of it in Keyboard.swift

now put the following code in Keyboard.swift

import UIKit
protocol KeyboardDelegate: class {
    //Called when keyboard button tapped
    func keyWasTapped(character: String)
}

protocol KeyboardDataSource: class {
    //Data array for keyboard
    func dataForKeyboard()-> [String]
}

class Keyboard: UIView {
    @IBOutlet var dataCollectionView: UICollectionView!
    static let collectionViewIdentifier = "DataSelectionCell"
    fileprivate let sectionInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
    // This variable will be set as the view controller so that
    // the keyboard can send messages to the view controller.
    weak var delegate: KeyboardDelegate?
    // This variable will ask for data to the view controller.
    weak var dataSource: KeyboardDataSource?

    // MARK:- keyboard initialization
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initializeSubviews()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        initializeSubviews()
    }
    // 1
    func initializeSubviews() {
        let xibFileName = "Keyboard" // xib extention not included
        let view = Bundle.main.loadNibNamed(xibFileName, owner: self, options: nil)?[0] as! UIView
        self.addSubview(view)
        view.frame = self.bounds
        //Register collection view cell
        let cellNib = UINib(nibName: Keyboard.collectionViewIdentifier, bundle: nil)
        dataCollectionView.register(cellNib, forCellWithReuseIdentifier: Keyboard.collectionViewIdentifier)
        dataCollectionView.delegate = self
        dataCollectionView.dataSource = self
    }
    // 2
    func viewTapped(gestureReconizer: UITapGestureRecognizer) {
        let point = gestureReconizer.location(in: dataCollectionView)
        let indexPath = dataCollectionView.indexPathForItem(at: point)
        // Trigger delegate for tap action
        dataCollectionView.delegate?.collectionView!(dataCollectionView, didSelectItemAt: indexPath!)
    }

}
// MARK:- UICollectionViewDelegate
extension Keyboard: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        // delegate (ie, the view controller)
        let dataArray = dataSource?.dataForKeyboard()
        let message = dataArray?[indexPath.row]
        self.delegate?.keyWasTapped(character: message!) // Inform delegate
    }
}
// MARK:- UICollectionViewDataSource
extension Keyboard: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if let dataArray = self.dataSource?.dataForKeyboard(){
            return dataArray.count
        }
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = dataCollectionView.dequeueReusableCell(withReuseIdentifier: Keyboard.collectionViewIdentifier, for: indexPath) as! DataSelectionCell
        let dataArray = dataSource?.dataForKeyboard()
        // Add tap gesture to TextView to send tap event, as TextView will cover entire cell
        let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped(gestureReconizer:)))
        cell.dataTextView.addGestureRecognizer(tap)
        cell.dataTextView.text = dataArray?[indexPath.row] //Set text for TextView
        return cell
    }
}
// MARK:- UICollectionViewDelegateFlowLayout
extension Keyboard : UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        //Setup grid like view
        //Device screen width
        let width = UIScreen.main.bounds.size.width
        //calculation of cell size
        return CGSize(width: ((width / 2) - 15), height: (collectionView.frame.height/2) - 20 )
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return sectionInsets.left
    }
}

The only method in the delegate which notifies when input view button tapped. KeyboardDelegate:

func keyWasTapped(character: String)

DataSource has only one method which accepts [String] for data KeyboardDataSource

func dataForKeyboard()-> [String]
  1. Here we will initialize subviews and configure DataSource and delegate for collection view
  2. This is UITapGestureRecognizer receiver action depending on the tap it calculate selection for collection view
  3. We have added UITapGestureRecognizer to the TextView to get the selection

Usage

Use of this input view is pretty simple as we use other input views

    var keyboardView: Keyboard? //Custom view refrence
    override func viewDidLoad() {
        super.viewDidLoad()
        exampleTextView.layer.borderColor = UIColor.lightGray.cgColor
        exampleTextView.layer.borderWidth = 1
        //1
        keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 216)) //Intialize custom input view
        keyboardView?.delegate = self //delegate
        keyboardView?.dataSource = self //datasource
        //2
        exampleTextView.inputView = keyboardView //Assign input view
        //Dismiss keyboard tap recognizer
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard))
        view.addGestureRecognizer(tap)
    }
  1. Initialize keyboard view with frame and set its delegate and dataSource to self
  2. Assign Keyboard view to TextView inputView

We will have to implement KeyboardDelegate method confirm the protocol

    extension ViewController: KeyboardDelegate {
        func keyWasTapped(character: String) {
            //3
            //Insert charaters to the TextView
            exampleTextView.insertText(character)
        }
    }
  1. Here we will add selected text to our textview

if you want to toggle input views then you should add IBAction for the button

    //4
    //Toggle between system and custom input view
    @IBAction func chatButtonDidTapped(_ sender: AnyObject) {
        if(exampleTextView.inputView == nil){
            // replace system keyboard with custom keyboard
            exampleTextView.inputView = keyboardView
        }
        else{
            exampleTextView.inputView = nil
        }
        exampleTextView.becomeFirstResponder()
        exampleTextView.reloadInputViews()
    }
  1. This is button action to toggle between system and custom keyboard.

This is how we have built custom input view, the final output will look like as Final_Sample_gif

You can customize it with TableView, replace with images to select the image.

You can download complete sample from Here

Custom Picker

screenCustom Picker is an easy to use and customizable alternate to UIPickerView. It is written in Swift language. The Custom Picker started as normal UIPicker but it was to limited in its design and methods. Also, I want to achieve a flat-picker with selected area background customizable which was not possible with default UIPicker.

So I made a use UITableView and customize its scroll to get the look and feel of UIPickerView. With the use of UITableView, I have made the picker flat. Now the second limitation of UIPickerView i.e. non-customizable selected area, for this I used an overlay view and customize it according to my need.

Requirements

It requires Xcode 7.0+ and Swift 2.3.

Application Usage

Custom Picker includes a sample of the project of Unit Conversion where a user can select the to and from units and input the number in one UITextField and the output will be shown in other UITextField.

Create a new picker

To use this picker you have to instantiate the CutomPickerView like instantiate any normal UIPickerView and implements it CustomPickerViewDelegate and CustomPickerViewDataSource methods

    let leftPickerView = CustomPickerView(frame: CGRectMake(0.0, 0.0, self.contentViewOfLeftpicker.frame.width,  self.contentViewOfLeftpicker.frame.height))

    leftPickerView.delegate = self
    leftPickerView.dataSource = self

    self.contentViewOfLeftpicker!.addSubview(leftPickerView)

Implement the Delegate and DataSource

The delegate methods that needs to be overridden are

func customPickerView(customPickerView: CustomPickerView, titleForRow row: Int, forLabel label: UILabel) -> String

 func customPickerView(customPickerView: CustomPickerView, didSelectRow row: Int)

func rowHeightForCustomPickerView(customPickerView: CustomPickerView) -> CGFloat

func labelStyleForCustomPickerView(customPickerView: CustomPickerView, forLabel label: UILabel)

func imageStyleForCustomPickerView(customPickerView: CustomPickerView, forImageView imageView: UIImageView)

Firstly you must rowHeightForCustomPickerView(_:)

func rowHeightForCustomPickerView(customPickerView: CustomPickerView) -> CGFloat {
        return 50.0
    }

Then you have to implement titleForRow method it sets the title for each row in a picker

func customPickerView(customPickerView: CustomPickerView, titleForRow row: Int, forLabel label: UILabel) -> String {

        return (label.tag == -1) ? pickerDataFullForm[row] as! String : pickerDataShortForm[row] as! String
    }

Next is the method that provides the didSelectRow

func customPickerView(customPickerView: CustomPickerView, didSelectRow row: Int) {

        leftPickerView.labelUnitFull.text = pickerDataFullForm[row] as? String
        leftPickerView.labelUnitShort.text = pickerDataShortForm[row] as? String

    }

Next method is labelStyleForCustomPickerView method this method is used to give custom style to UILabel in CustomPickerView

func labelStyleForCustomPickerView(customPickerView: CustomPickerView, forLabel label: UILabel) {
        if (label.tag == -1) {

            label.textColor = UIColor.blackColor()
            label.font = UIFont(name: "HelveticaNeue-Bold", size: 20.0)
        }else{

            label.textColor = UIColor.lightGrayColor()
            label.font = UIFont(name: "HelveticaNeue-Bold", size: 15.0)
        }
    }

And the last delegate method is imageStyleForCustomPickerView this is used to give any background image to the overlay view.

    func imageStyleForCustomPickerView(customPickerView: CustomPickerView, forImageView imageView: UIImageView) {
        if customPickerView == leftPickerView {
            leftPickerView.arrowImage.image = UIImage(named: "LeftArrow")
        }
    }

CustomPickerViewDataSource

The CustomPickerView consists of only one data source method. This method returns the number of rows in that picker:

 func numberOfRowsInCustomPickerView(customPickerView: CustomPickerView) -> Int

Using Genymotion in Android

Let’s get familiar with Genymotion.

Genymotion is the most powerful Android emulator for app developers & testers.

Developers can install the plugin of Genymotion in Android Studio plugin with few simple steps:

  1. Click File–> Settings
  2. Click on Plugins tabs left side on Settings window.
    settings
  3. Click Browse Repositories and search for Genymotion.
    genymotion_plugin
    On the right side of Browse Repositories pop up, there will be a button with name “Install”.
  4. Click on install button.
  5. Restart your Android Studio IDE. Now you can see, Genymotion is installed in Android studio.


How to use the Genymotion for the app?

  • After installation of Genymotion plugin, there will be a phone like an icon on the toolbar of Android Studio.
  • After clicking that icon Genymotion Device Manager will open, where you can see the list of available Genymotion virtual devices.
  • Select one of them or you can create the virtual device by clicking on New button.
  • Creating new virtual device will show a popup shown below,virtual_device_creation_wizard
    Where you have options to choose Android versions and Device model after that click on Next button.

    • You can choose the name for the virtual device shown as below,virtual_device_name
    • Click Next and download and install will start for the virtual device.That’s all. Now you can click on start button to start Genymotion virtual device.Now you can run your App on this device. Just hit Run button on your Android Studio’s toolbar, choose your virtual device from Available Virtual Devices and it will run your project on it.
    • To avoid the issues in your android app you can follow Do’s and Don’ts for Android this blog.