Custom fonts TextView in Android

Custom fonts TextView in Android

Nowadays, than ever before, everybody would like to use custom fonts in android TextViews.
It’s very easy to do it.

First step is to put the font in assets/fonts/Lato_Heavy.ttf

In this example we use Lato_Regular.ttf

Now, we are going to make a custom TextView, like this:

com.thedeveloperworldisyours
 
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
 
public class TextView_Lota_Heavy extends TextView {


    public TextView_Lota_Heavy(Context context) {
        super(context);
        applyCustomFont(context);
    }

    public TextView_Lota_Heavy(Context context, AttributeSet attrs) {
        super(context, attrs);
        applyCustomFont(context);
    }

    public TextView_Lota_Heavy(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        applyCustomFont(context);
    }

    private void applyCustomFont(Context context) {
        Typeface customFont = FontCache.getTypeface("fonts/Lato_Heavy.ttf", context);
        setTypeface(customFont);
    }
}

And FontCache

public class FontCache {
    private static HashMap<String, Typeface> fontCache = new HashMap<>();

    public static Typeface getTypeface(String fontname, Context context) {
        Typeface typeface = fontCache.get(fontname);

        if (typeface == null) {
            try {
                typeface = Typeface.createFromAsset(context.getAssets(), fontname);
            } catch (Exception e) {
                return null;
            }

            fontCache.put(fontname, typeface);
        }

        return typeface;
    }
}

when you want to load one of your custom fonts, you’d say something like:

Typefaces.get("Lato_Heavy");

basically this class ensures Android only loads each font once per instance of your app. the tradeoff, of course, is that each requested typeface object will remain in memory until your app is totally stopped by the OS (even though a given activity may not require each font).

Now we add our custom TextView in our layou.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background" >
  
    <com.thedeveloperworldisyours.TextView_Lota_Regular
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
  
</LinearLayout>

You can download this code: Download code

CSV File Validation In PHP (Part III)

This is the third and last part o the explanation of how to implement a csv file validation in php, using the Strategy Pattern.

If you remember the first post, we started implementing simple validations for each column, and in the second post, we wrote the main class that will take care of processing the whole CSV file.

Now, it’s time to implement the missing piece, to merge both parts. Basically, we need a class that should act as interface between our analyzer and the validators. We should apply a different validation’s implementation depending on the csv field.

In order to do that, I turn the field’s name into the class name that should take care of the validation of the field. In example, if the field is called “short_description”, then its validator class should be ShortDescription (UpperCamelCase). In order to separate the validators by phases, I prepend the phase with an underscore, so for instance, the previous example would eventually be Lexical_ShortDescription and Semantic_ShortDescription.

Then, all I have to do is instantiate the class, and call its method “validate” with the given input, and return the result.

This how it looks like:

class ValidatorContext {

private $strategy;
private $warnings;

/*
* Create the instance of the validator by building the class name with the UpperCamelCase format
* Generate a warning if the validator wasn't found, and create a generic validator instance
*
* @param $type string type of analysis
* @param $strategy string validator strategy class name
* @param $optData array optional data passed to the semantic validators
* @return void
*/
function __construct($type, $strategy, $profile, $optData = null) {
$this->warnings = array();
$validator = ucfirst($type) . '_' . str_replace(' ', '', ucwords(str_replace('_', ' ', $validator)));
if(class_exists($validator)) {
$this->strategy = new $validator($profile, $optData);
}else {
$this->strategy = new Generic_Validator();
$this->warnings[] = sprintf('Strategy %s (%s) is not implemented for the %s analizer ' . "\n", $strategy, $validator, $type);
}
}

/**
* Remove elements from memory
* @return void
*/
function __destruct() {
unset($this->strategy);
}

/**
* getTokens
* Return the tokens retrieved from the validator
* @return array
*/
public function getTokens() {
return $this->strategy->getTokens();
}

/**
* getErrors
* Return the errrors found during the validation
* @return array
*/
public function getErrors() {
return $this->strategy->getErrors();
}

/**
* getWarnings
* Return the warnings found during the validation
* @return array
*/
public function getWarnings() {
return $this->warnings;
}

/**
* getErrorMsg
     * Return the errror description to help the user to solve the problem
* @param $input string|array
* @return string
*/
public function getErrorMsg($input) {
return $this->strategy->getErrorMsg($input);
}

/**
* validate
* @access public
* @param $input mixed input data of the csv
* @return bool whether this data is valid or not for current validator
*/
public function validate(&$input) {
//Uncomment the line below to debug
//echo get_class($this->_strategy) . ": " . $input . "\n";
return $this->strategy->validate($input);
}

}

And basically, that’s about it. You might thrown an exception if there is no validation found for a certain field, but in my case its enough to just bypass the validation, so the Generic_Validator class, will always return true.

I hope this can help you to implement your own csv validation in php. If you want to download the source code of the whole application, I’ll put the link with some working examples of usage included during this week.

Updated on 14/04/2013

I’ve created a git repository with the source code of the CSV validator. I’ve included an example of usage with some demo files as well. All you have to do is clone the repository and execute “example.php” from php-cli.

You get the source code of the validator from here.

Add a textview and a button to linear layout programmatically

It’s very simple to add textviews and buttons to linear layout programmatically, just follow this steps. The fist step. Add a LinearLayout in .xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_linear_layout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/thewordis"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

</LinearLayout>

Now in .class add:
1) add LinearLayout
2) add LayoutParams
3) add TextView
4) add Button
5) add the TextView and the Button to View

import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ClassTheDeveloperWorldIsYours extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.the_developer_world_is_yours);

        //added LInearLayout
        LinearLayout linearLayout = (LinearLayout) findViewById(R.id.activity_linear_layout);

        //added LayoutParams
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        linearLayout.setOrientation(LinearLayout.VERTICAL);

        //add textView
        TextView textView = new TextView(this);
        textView.setText("The developer world is yours");
        textView.setId(1);
        textView.setLayoutParams(params);

        // added Button
        Button button = new Button(this);
        button.setText("thedeveloperworldisyours");
        button.setId(2);

        //added the textView and the Button to LinearLayout
        linearLayout.addView(textView);
        linearLayout.addView(button);

    }
}

You can download this code:

Download code

CSV File Validation In PHP (Part II)

If you remember my previous post regarding CSV validation, I explained how to implement a different validator for each field, and phase, using the Strategy Design Pattern. For instance, in the lexical phase, I was checking for the correctness of the SKU field regarding the lenght of the string, and the absence of forbidden characters. In the semantic phase, depending on if it’s an update or an import task, I was checking for the existence or absence of the provided SKUs list in the database.

One of the big advantages of this implementation, is that it’s very easy to implement unitary tests for each validator, as they are almost totally independent from each other. I said almost because the return values of the lexical validators are the input of the semantic ones, so there is some kind of dependency there. For instance, the “store” field used to be a string containing the code of the store, but eventually, we allowed to put several comma-separated store codes on the field. This required changes not only in the regular expressions of the lexical validator, but also on any semantic validator that depended on the store tokens, as they’ll be expecting an input string, but instead, they’ll get an array.

I could keep on talking about the pros and cons of this approach, but it’s out of the scope of this post. Our goal is to implement a CSV file validation, so, let’s focus on the implementation of the main class which will take care or reading the CSV file, and execute the proper validator for each column.

For the shake of readability on the blog, I’ve un-indented one level the methods’ code. This is how the lexical phase looks like:

class Analyzer {

    const LEXICAL = 'lexical';
    const SEMANTIC = 'semantic';

    /**
     * Allowed profiles
     */
    private static $_PROFILES = array('import', 'update');

    private $_validators;
    private $_columnIndexes;
    private $_requiredFields;
    private $_profile;
    private $_errors;

function __construct(array $required, $profile) {
    $this->_validators = array();
    $this->_columnIndexes = array();
    $this->_errors = array();
    $this->_requiredFields = $required;
    $this->_profile = $profile;
    if(!in_array($profile, self::$_PROFILES)) {
        die('Unknown profile specified.');
    }
}
/*
 * Perform the lexical analysis over the CSV
 * Iterate over the file and exit if an error is found
 *
 * @param $file string full path of the csv file
 * @return bool whether the file is valid (from a lexical point of view) or not
 */
protected function lexical($file) {
    if (!file_exists($file))  {
        return false;
    } else {
        $delimiter = self::getDelimiter($file);
    }

    $handle = fopen($file, 'r');

    //Parse the first row, instantiate all the validators
    $valid = $this->parseFirstRow(fgetcsv($handle, 0, $delimiter));
    //Number of columns specified on the header
    $num_columns = sizeOf($this->_columnIndexes);
    //line number count
    $i = 1;

    while(($data = fgetcsv($handle, 0, $delimiter)) !== FALSE && $valid) {
        $errors = array();

        //For each column
        foreach ($data as $key => $value) {

            //Skip all columns without header
            if($key >= $num_columns) {
                break;
            }

            $value = trim($value);

            //Validate
            $errors[$this->_columnIndexes[$key]] = $this->_validators[$key]->validate($value);

            $valid = $valid && $errors[$this->_columnIndexes[$key]];
        }

        //If any error was found, exit
        if(!$valid) {
            $filtered_errors = array_keys($errors, false);
            if(count($filtered_errors) > 0) {
		//Store the errors founds on the current line
                $this->_errors[$i] = $filtered_errors;
            }
            break;
        }
        $i++;
    }
    fclose($handle);

    return $valid;
}
/**
 * parseFirstRow
 * Check that the column names aren't duplicated
 * Ensure all required fields are present
 * Create the instances of each validator.
 *
 * @param array $data
 * @access protected
 * @return bool
 */
protected function parseFirstRow(array $data) {
    $valid = true;
    //Clean the data
    $data = array_filter(array_map('trim', array_map('strtolower', $data)));

    //Ensure that there aren't duplicated columns
    $dupes = array_diff_key($data, array_unique($data));
    if(!empty($dupes)) {
        $this->_errors[] = sprintf('The following columns are duplicated on the CSV: "%s".', implode($dupes, '", "'));
        $valid = false;
    }

    //Ensure all required columns are present
    if($valid &&
        //The number of columns is lower than the required fields, we don't need to keep checking, some columns are missing.
        (count($data) < count($this->_requiredFields) ||
        //The number of optional fields must match with the number of fields that are not required, otherwise something is missing.
        count(array_diff($data, $this->_requiredFields)) !== (count($data) - count($this->_requiredFields)) ||
        //If the operation is an import, either categories or category_ids must be present
        ($this->_profile == 'import' && !(in_array('categories', $data) || in_array('category_ids', $data))))) {

            $required = implode(array_diff($this->_requiredFields, $data), '", "');
            if($this->_profile == 'import' && !in_array('category_ids', $data) && !in_array('categories', $data)) {
                if($required) {
                    $required .= '" and "categories" or "category_ids';
                } else {
                    $required = 'categories" or "category_ids';
                }
            }
            $this->_errors[] = sprintf('The following columns are missing on the CSV: "%s".', $required);
            $valid = false;
        }

    if($valid) {
        //Instantiate all the lexical validators
        foreach ($data as $key => $value) {
            $this->_validators[$key] = new ValidatorContext(Analyzer::LEXICAL, $value, $this->_profile);
            $this->_columnIndexes[$key] = $value;
        }
    }
    return $valid;
}
/**
 * getDelimiter
 * Try to detect the delimiter character on a CSV file, by reading the first row.
 *
 * @param mixed $file
 * @access public
 * @return string
 */
public static function getDelimiter($file) {
    $delimiter = false;
    $line = '';
    if($f = fopen($file, 'r')) {
        $line = fgets($f); // read until first newline
        fclose($f);
    }
    if(strpos($line, ';') !== FALSE && strpos($line, ',') === FALSE) {
        $delimiter = ';';
    } else if(strpos($line, ',') !== FALSE && strpos($line, ';') === FALSE) {
        $delimiter = ',';
    } else {
        die('Unable to find the CSV delimiter character. Make sure you use "," or ";" as delimiter and try again.');
    }
    return $delimiter;
}
}

I hope that the code is pretty much self-explanatory, but anyway I’ll summarize the process.

It all begins with the instantiation of the Analyzer class, where you provide the profile, and the required fields for this task.
Then, the lexical method is called with the full path of the CSV file to be processed. If the file exists, we firstly try to detect the delimiter used, which should be a comma or a semicolon.

Afterwards, the first row is parsed by cleaning the data, and checking for the correctness of the fields, ensuring there are not duplicated fields, and that all the required fields are present. If everything went as expected, we call the ValidatorContext class providing the fieldname, and we’ll get the proper validator instatiated.

Finally, we iterate over the CSV, ensuring that all the validations are passed, stopping the process in case of error, and saving the field and the line where the problem was found.

That’s all from now, in the next post I’ll show the last piece of the puzzle, which is the implementation of the ValidatorContext class, where we will be able to unify the whole process.

Percentage of screen in android

For doing percentage of screen in android, we use PercentRelativeLayout:

Subclass of RelativeLayout that supports percentage based dimensions and margins. You can specify dimension or a margin of child by using attributes with “Percent” suffix.

The attributes that you can use are:

  • layout_widthPercent
  • layout_heightPercent
  • layout_marginPercent
  • layout_marginLeftPercent
  • layout_marginTopPercent
  • layout_marginRightPercent
  • layout_marginBottomPercent
  • layout_marginStartPercent
  • layout_marginEndPercent
  • layout_aspectRatio

In our dependencies

compile 'com.android.support:percent:22.2.0'

Follow this example:

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.thedeveloperworldisyours.percentrelativelayouts.MainActivity">
 
    <TextView
        android:id="@+id/activity_main_text_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerVertical="true"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="width 69%"
        app:layout_heightPercent="10%"
        app:layout_marginLeftPercent="4%"
        app:layout_widthPercent="69%" />
 
    <TextView
        android:id="@+id/activity_main_second_text_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/activity_main_text_view"
        android:background="@android:color/holo_red_dark"
        android:gravity="center"
        android:text="width 23%"
        app:layout_heightPercent="10%"
        app:layout_marginRightPercent="4%"
        app:layout_widthPercent="23%" />
</android.support.percent.PercentRelativeLayout>

We can see a big example:
null

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/activity_calculator_black_transparent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingTop="90dp"
    android:weightSum="5"
    tools:context="com.thedeveloperworldisyours.unitconverterpro.calculator.CalculatorActivity">

    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerVertical="true"
        android:background="@drawable/calculator_background"
        app:layout_heightPercent="53%"
        app:layout_marginLeftPercent="2%"
        app:layout_marginRightPercent="2%"
        app:layout_widthPercent="100%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.AutoResizeTextView
        android:id="@+id/activity_calculator_result"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_above="@+id/activity_calculator_divide"
        android:layout_toLeftOf="@+id/activity_calculator_remove"
        android:background="@drawable/calculator_text"
        android:inputType="text"
        android:maxLines="1"
        android:gravity="end"
        android:paddingRight="12dp"
        android:paddingLeft="12dp"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_marginLeftPercent="4%"
        app:layout_widthPercent="69%" />

    <ImageButton
        android:id="@+id/activity_calculator_remove"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_above="@+id/activity_calculator_divide"
        android:layout_alignParentRight="true"
        android:src="@mipmap/ic_backspace_calculator"
        android:background="@drawable/calculator_remove_button"
        app:layout_heightPercent="10%"
        app:layout_marginRightPercent="4%"
        app:layout_widthPercent="23%" />

    <!--fourth-->

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_seven"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_above="@+id/activity_calculator_multiply"
        android:layout_toLeftOf="@+id/activity_calculator_eight"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_seven"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_marginLeftPercent="4%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_eight"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_above="@+id/activity_calculator_multiply"
        android:layout_toLeftOf="@+id/activity_calculator_nine"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_eight"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_nine"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_above="@+id/activity_calculator_multiply"
        android:layout_toLeftOf="@+id/activity_calculator_divide"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_nine"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.BlackplotanButton
        android:id="@+id/activity_calculator_divide"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_above="@+id/activity_calculator_multiply"
        android:layout_alignParentRight="true"
        android:background="@drawable/calculator_operator_button"
        android:text="@string/activity_calculator_divide"
        android:textSize="@dimen/activity_calculator_size_text_operator"
        app:layout_heightPercent="10%"
        app:layout_marginRightPercent="4%"
        app:layout_widthPercent="23%" />

    <!--third-->

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_four"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/activity_calculator_five"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_four"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_marginLeftPercent="4%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_five"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/activity_calculator_six"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_five"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_six"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/activity_calculator_multiply"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_six"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.BlackplotanButton
        android:id="@+id/activity_calculator_multiply"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:background="@drawable/calculator_operator_button"
        android:text="@string/activity_calculator_multiply"
        android:textSize="@dimen/activity_calculator_size_text_operator"
        app:layout_heightPercent="10%"
        app:layout_marginRightPercent="4%"
        app:layout_widthPercent="23%" />

    <!--second-->

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_one"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_below="@+id/activity_calculator_multiply"
        android:layout_toLeftOf="@+id/activity_calculator_two"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_one"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_marginLeftPercent="4%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_two"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_below="@+id/activity_calculator_multiply"
        android:layout_toLeftOf="@+id/activity_calculator_three"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_two"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_three"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_below="@+id/activity_calculator_multiply"
        android:layout_toLeftOf="@+id/activity_calculator_diminish"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_three"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.BlackplotanButton
        android:id="@+id/activity_calculator_diminish"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/activity_calculator_multiply"
        android:background="@drawable/calculator_operator_button"
        android:text="@string/activity_calculator_diminish"
        android:textSize="@dimen/activity_calculator_size_text_operator"
        app:layout_heightPercent="10%"
        app:layout_marginRightPercent="4%"
        app:layout_widthPercent="23%" />

    <!--last-->

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_dot"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_below="@+id/activity_calculator_diminish"
        android:layout_toLeftOf="@+id/activity_calculator_zero"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_dot"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_marginLeftPercent="4%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.StarjediButton
        android:id="@+id/activity_calculator_zero"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_below="@+id/activity_calculator_diminish"
        android:layout_toLeftOf="@+id/activity_calculator_equals"
        android:background="@drawable/calculator_button"
        android:text="@string/activity_calculator_zero"
        android:textSize="@dimen/activity_calculator_size_text"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.BlackplotanButton
        android:id="@+id/activity_calculator_equals"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_below="@+id/activity_calculator_diminish"
        android:layout_toLeftOf="@+id/activity_calculator_add"
        android:background="@drawable/calculator_equal_button"
        android:text="@string/activity_calculator_equals"
        android:textSize="@dimen/activity_calculator_size_text_operator"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="23%" />

    <com.thedeveloperworldisyours.unitconverterpro.common.view.BlackplotanButton
        android:id="@+id/activity_calculator_add"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/activity_calculator_diminish"
        android:background="@drawable/calculator_operator_button"
        android:text="@string/activity_calculator_plus"
        android:textSize="@dimen/activity_calculator_size_text_operator"
        app:layout_heightPercent="10%"
        app:layout_marginRightPercent="4%"
        app:layout_widthPercent="23%" />
</android.support.percent.PercentRelativeLayout>