Wednesday, 23 March 2016

How to create a Calculator App for Android

Layouts:

@ home.xml Layout: This layout is the welcome layout for Quick Calculator application. In this layout, a wallpaper is set as background of the layout. While we start this application, this layout runs for 3 seconds.
Listing 1: home.xml layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/calc"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="35dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="25dp"
        android:text="@string/app_name"
        android:textColor="#000"
        android:textSize="25sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="25dp"
        android:layout_marginLeft="70dp"
        android:layout_weight="0.04"
        android:text="@string/app_name_slogan"
        android:textColor="#000"
        android:textSize="15sp" />

</LinearLayout>

Java Class Files:

Every Android project contains a "res" (reources) folder. This folder is meant to comprise of number of subfolders.
Listing 2: calc.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".Home"
    android:background="#fff" >

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/disp"
        android:id = "@+id/display"
        android:hint="@string/dispHint" />
   <LinearLayout android:orientation="horizontal"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:gravity="center"
       android:paddingTop="20dp">
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/seven"
     android:text="@string/seven"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/eight"
     android:text="@string/eight"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/nine"
     android:text="@string/nine"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/div"
     android:text="@string/div"
 /> 
   </LinearLayout>
    <LinearLayout android:orientation="horizontal"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:gravity="center"
       android:paddingTop="20dp">
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/four"
     android:text="@string/four"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/five"
     android:text="@string/five"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/six"
     android:text="@string/six"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/mul"
     android:text="@string/mul"
 /> 
   </LinearLayout>
   <LinearLayout android:orientation="horizontal"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:gravity="center"
       android:paddingTop="20dp">
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/one"
     android:text="@string/one"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/two"
     android:text="@string/two"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/three"
     android:text="@string/three"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/sub"
     android:text="@string/sub"
 /> 
   </LinearLayout>
   <LinearLayout android:orientation="horizontal"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center"
       android:gravity="center"
       android:paddingTop="20dp">
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/cancel"
     android:text="@string/cancel"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/zero"
     android:text="@string/zero"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/equal"
     android:text="@string/equal"
 />
    <Button 
     android:layout_width="55dp"
     android:layout_height="wrap_content"
     android:id = "@+id/add"
     android:text="@string/add"
 />
   </LinearLayout>
</LinearLayout>


Home class defined in the Home.java file.
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class Home extends Activity{

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.home);
  Thread th = new Thread(){
   public void run(){
    try{
     sleep(1000);
    }
    catch(Exception e){
     e.printStackTrace();
    }
    finally{
     onPause();
     startActivity(new Intent("com.one.slate.CALC"));
    }
   }
  };
  th.start();
 }
 @Override
 public void onPause(){
  super.onPause();
  finish();
 }
 
}    

Calculator class defind into the Calc.java file.
import android.os.Bundle;
import android.app.Activity;
import android.text.Editable;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Calc extends Activity implements View.OnClickListener{
 
 Button one, two, three, four, five, six, seven, eight, nine, zero, add, sub, mul, div, cancel, equal;
 EditText disp;
 int op1;
 int op2;
 String optr;
 
 @Override
    protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        
        one = (Button) findViewById(R.id.one);
        two = (Button) findViewById(R.id.two);
        three = (Button) findViewById(R.id.three);
        four = (Button) findViewById(R.id.four);
        five = (Button) findViewById(R.id.five);
        six = (Button) findViewById(R.id.six);
        seven = (Button) findViewById(R.id.seven);
        eight = (Button) findViewById(R.id.eight);
        nine = (Button) findViewById(R.id.nine);
        zero = (Button) findViewById(R.id.zero);
        add = (Button) findViewById(R.id.add);
        sub = (Button) findViewById(R.id.sub);
        mul = (Button) findViewById(R.id.mul);
        div = (Button) findViewById(R.id.div);
        cancel = (Button) findViewById(R.id.cancel);
        equal = (Button) findViewById(R.id.equal);
        
        disp = (EditText) findViewById(R.id.display);
        
        try{
         one.setOnClickListener(this);
    
         two.setOnClickListener(this);
         
         three.setOnClickListener(this);
         
         four.setOnClickListener(this);
         
         five.setOnClickListener(this);
         
         six.setOnClickListener(this);
         
         seven.setOnClickListener(this);
         
         eight.setOnClickListener(this);
         
         nine.setOnClickListener(this);
         
         zero.setOnClickListener(this);
         
         cancel.setOnClickListener(this);
         
         add.setOnClickListener(this);
  
         sub.setOnClickListener(this);
         
         mul.setOnClickListener(this);
         
         div.setOnClickListener(this);
         
         equal.setOnClickListener(this);
        }
        catch(Exception e){
         
        }
    }
 public void operation(){
  if(optr.equals("+")){
   op2 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
   op1 = op1 + op2;
   disp.setText("Result : " + Integer.toString(op1));
  }
  else if(optr.equals("-")){
   op2 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
   op1 = op1 - op2;
   disp.setText("Result : " + Integer.toString(op1));
  }
  else if(optr.equals("*")){
   op2 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
   op1 = op1 * op2;
   disp.setText("Result : " + Integer.toString(op1));
  }
  else if(optr.equals("/")){
   op2 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
   op1 = op1 / op2;
   disp.setText("Result : " + Integer.toString(op1));
  }
 }
 @Override
 public void onClick(View arg0) {
  Editable str =  disp.getText();
  switch(arg0.getId()){
   case R.id.one:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(two.getText());
    disp.setText(str);
   break;
   case R.id.two:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(two.getText());
    disp.setText(str);
   break;
   case R.id.three:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(three.getText());
    disp.setText(str);
   break;
   case R.id.four:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(four.getText());
    disp.setText(str);
   break;
   case R.id.five:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(five.getText());
    disp.setText(str);
   break;
   case R.id.six:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(six.getText());
    disp.setText(str);
   break;
   case R.id.seven:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(eight.getText());
    disp.setText(str);
   break;
   case R.id.eight:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(nine.getText());
    disp.setText(str);
  
   break;
   case R.id.nine:
    if(op2 != 0){
     op2 = 0;
     disp.setText("");
    }
    str = str.append(zero.getText());
    disp.setText(str);
  
   break;
   case R.id.cancel:
    op1 = 0;
    op2 = 0;
    disp.setText("");
    disp.setHint("Perform Operation :)");
  
   break;
   case R.id.add:
    optr = "+";
    if(op1 == 0){
   op1 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
    }
   else if(op2 != 0){
   op2 = 0;
   disp.setText("");
    }
    else{
   op2 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
   op1 = op1 + op2;
   disp.setText("Result : " + Integer.toString(op1));
    }
   break;
   case R.id.sub:
    optr = "-";
    if(op1 == 0){
   op1 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
    }
    else if(op2 != 0){
     op2 = 0;
    disp.setText("");
    }
    else{
   op2 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
   op1 = op1 - op2;
   disp.setText("Result : " + Integer.toString(op1));
    }
   break;
   case R.id.mul:
    optr = "*";
    if(op1 == 0){
     op1 = Integer.parseInt(disp.getText().toString());
     disp.setText("");
    }
    else if(op2 != 0){
     op2 = 0;
    disp.setText("");
    }
    else{
   op2 = Integer.parseInt(disp.getText().toString());
    disp.setText("");
   op1 = op1 * op2;
   disp.setText("Result : " + Integer.toString(op1));
    }
   break;
   case R.id.div:
   optr = "/";
  if(op1 == 0){
  op1 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
    }
  else if(op2 != 0){
   op2 = 0;
   disp.setText("");
    }
    else{
   op2 = Integer.parseInt(disp.getText().toString());
   disp.setText("");
   op1 = op1 / op2;
  disp.setText("Result : " + Integer.toString(op1));
    }
  break;
  case R.id.equal:
 if(!optr.equals(null)){
     if(op2 != 0){
    if(optr.equals("+")){
    disp.setText("");
    /*op1 = op1 + op2;*/
   disp.setText("Result : " + Integer.toString(op1));
     }
    else if(optr.equals("-")){
     disp.setText("");/*
    op1 = op1 - op2;*/
    disp.setText("Result : " + Integer.toString(op1));
     }
    else if(optr.equals("*")){
  dispsetText("");/*
   op1 = op1 * op2;*/
  disp.setText("Result : " + Integer.toString(op1));
      }
    else if(optr.equals("/")){
     disp.setText("");/*
    op1 = op1 / op2;*/
    disp.setText("Result : " + Integer.toString(op1));
      }
     }
     else{
      operation();
     }
    }
   break;
  }
 }
} 


XML : AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.androidvinod"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.one.slate.Home"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.one.slate.Calc"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="com.one.slate.CALC" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Android Material Design

You might have heard of android Material Design which was introduced in Android Lollipop version. In Material Design lot of new things were introduced like Material Theme, new widgetscustom shadowsvector drawables and custom animations



Material Design Color Customization

Material Design provides set of properties to customize the Material Design Color theme. But we use five primary attributes to customize overall theme.
colorPrimaryDark – This is darkest primary color of the app mainly applies to notification bar background.
colorPrimary – This is the primary color of the app. This color will be applied as toolbar background.
textColorPrimary – This is the primary color of text. This applies to toolbar title.

windowBackground – This is the default background color of the app.

Creating Material Design Theme

1. In Android Studio, go to File ⇒ New Project and fill all the details required to create a new project. When it prompts to select a default activity, select Blank Activity and proceed.
2. Open res ⇒ values ⇒ strings.xml and add below string values.
strings.xml
<resources>
    <string name="app_name">Material Design</string>
    <string name="action_settings">Settings</string>
    <string name="action_search">Search</string>
    <string name="drawer_open">Open</string>
    <string name="drawer_close">Close</string>
    <string name="nav_item_home">Home</string>
    <string name="nav_item_friends">Friends</string>
    <string name="nav_item_notifications">Messages</string>
    <!-- navigation drawer item labels  -->
    <string-array name="nav_drawer_labels">
        <item>@string/nav_item_home</item>
        <item>@string/nav_item_friends</item>
        <item>@string/nav_item_notifications</item>
    </string-array>
    <string name="title_messages">Messages</string>
    <string name="title_friends">Friends</string>
    <string name="title_home">Home</string>
</resources>
3. Open res ⇒ values ⇒ colors.xml and add the below color values. If you don’t find colors.xml, create a new resource file with the name.
colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#F50057</color>
    <color name="colorPrimaryDark">#C51162</color>
    <color name="textColorPrimary">#FFFFFF</color>
    <color name="windowBackground">#FFFFFF</color>
    <color name="navigationBarColor">#000000</color>
    <color name="colorAccent">#FF80AB</color>
</resources>
4. Open res ⇒ values ⇒ dimens.xml and add below dimensions.
dimens.xml
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="nav_drawer_width">260dp</dimen>
</resources>
5. Open styles.xml under res ⇒ values and add below styles. The styles defined in this styles.xml are common to all the android versions. Here I am naming my theme as MyMaterialTheme.
styles.xml
<resources>
    <style name="MyMaterialTheme" parent="MyMaterialTheme.Base">
    </style>
    <style name="MyMaterialTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
     
</resources>
6. Now under res, create a folder named values-v21. Inside values-v21, create another styles.xml with the below styles. These styles are specific to Android Lollipop only.
styles.xml
<resources>
    <style name="MyMaterialTheme" parent="MyMaterialTheme.Base">
        <item name="android:windowContentTransitions">true</item>
        <item name="android:windowAllowEnterTransitionOverlap">true</item>
        <item name="android:windowAllowReturnTransitionOverlap">true</item>
        <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
        <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
    </style>
</resources>
7. Now we have the basic Material Design styles ready. In order to apply the theme, openAndroidManifest.xml and modify the android:theme attribute of <application> tag.
android:theme="@style/MyMaterialTheme"
So after applying the theme, your AndroidManifest.xml should look like below.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
    package="androidvinod.materialdesign" >
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/MyMaterialTheme" >
        <activity
            android:name=".activity.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

 Adding the Toolbar (Action Bar)

Adding the toolbar is very easy. All you have to do is, create a separate layout for the toolbar and include it in other layout wherever you want the toolbar to be displayed.
8. Create an xml file named toolbar.xml under res ⇒ layout and addandroid.support.v7.widget.Toolbar element. This create the toolbar with specific height and theming.
toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
9. Open the layout file of your main activity (activity_main.xml) and add the toolbar using <include/>tag.
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:orientation="vertical">
        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar" />
    </LinearLayout>
</RelativeLayout>
Once the icon is imported, open menu_main.xml located under res ⇒ menu and add the search menu item as mentioned below.
menu_main.xml
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity">
    <item
        android:id="@+id/action_search"
        android:title="@string/action_search"
        android:orderInCategory="100"
        android:icon="@drawable/ic_action_search"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        app:showAsAction="never" />
</menu>
13. Now open your MainActivity.java and do the below changes.
> Extend the activity from AppCompatActivity
> Enable the toolbar by calling setSupportActionBar() by passing the toolbar object.
> Override onCreateOptionsMenu() and onOptionsItemSelected() methods to enable toolbar action items.
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {
    private Toolbar mToolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}