Pages

Showing posts with label ArrayAdapter. Show all posts
Showing posts with label ArrayAdapter. Show all posts

Tuesday, September 24, 2013

File Chooser

In this post, you learn to implement a File Chooser in Android. Some apps such as text viewer, text editor, and other apps that allow the user to select a file from the Android to open should provide a dialog that the user can select the file easily. In Java, we have JFileChooser and in VB.NET or C# we have OpenFileDialog. However, in Android, i have not found a file chooser library to do such the same thing.
To begin, please open the Eclipse and create a new Android project called FileChooser. In this File Chooser implementation, i use the AlertDialog class to show a file chooser dialog. On the dialog, there are one ListView, and two Buttons. The ListView displays the files and directories. The first Button takes the user back up one level of the directories structure. The second Button is pushed to close the dialog.


FileChooser for Android



You no need to create a layout file for the dialog to show the ListView, and the two Buttons as these components will be added to the dialog by code in AndFileChooser.java file.
Each item of the ListView contains both icon and text. If the item represents the directory, the icon will be directory icon. Otherwise, it is the file icon. In default, the ListView provided by Android is simple ListView that its items show only text. To customize the ListView to display both icon and text, first to do is changing the layout file that is applied to each item of the ListView. The layout file in this File Chooser implementation is called listlayout.xml in layout directory. Its content is shown below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="5dip"
    >


<ImageView
    android:id="@+id/icon"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:padding="5sp"
    android:contentDescription="iconimage"
 />

<TextView
    android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10sp"
        android:textSize="20sp"
        android:textColor="#0000ff"
        android:textStyle="bold" >
</TextView>
</LinearLayout>


As you see in the listlayout.xml file, there are two components in this layout. First one is the ImageView to display the icon of an item. The second component is TextView to display the text of the item.
You should note that this layout is not the layout of the ListView itselft. Instead, it is the layout of an item of the ListView. The ListView will be defined in code (int AndFileChooser.java).

Another layout file that you need to create is called selection_style.xml. This layout is applied to the selected item of the list. The selection_style.xml file is stored in the drawable directory. In this directory, you also need two small images--directory and file images. These images represent the directory and file icons that show on the ListView (see the picture above).

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 
    <item>
        <shape>
            <gradient
                android:startColor="#dfdfdf"
                android:endColor="#dfdfdf"            
                android:angle="180" />
        </shape>      
    </item>
</selector>

Now take a look at the AndFileChooser. java file. This file contains a class called AndFileChooser. The AndroidFileChooser class can be used anywhere in your app to display the file chooser dialog.

AndFileChooser.java

package com.example.filechooser;
import java.io.File;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class AndFileChooser {
private int RESULT=0;
private static final int RESULT_OK=1;
private String path;
private Context context;
private  String att_path;
private ListView l;

AndFileChooser(String path, Context context){
this.path=path;
this.context=context;
}

public void show(){
//create a dialog to show a list of files and directories
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setCancelable(true);
builder.setPositiveButton("OK", new OkOnClickListener());
builder.setNeutralButton("Up",null);
builder.setView(getList(path));
AlertDialog dialog = builder.create();      
dialog.show();
//override the default dialog default behavior when the Up button is pressed
dialog.getButton(Dialog.BUTTON_NEUTRAL).setOnClickListener(new View.OnClickListener() {

public void onClick(View arg0) {
upOneLevel();
}
});
}

private void upOneLevel(){
    //go back on directory
    path=path.substring(0, path.lastIndexOf("/"));
if(path.length()<=0)
path="/";
listFiles();
   }
   private final class OkOnClickListener implements DialogInterface.OnClickListener {
    public void onClick(DialogInterface dialog, int which) {
    RESULT=RESULT_OK;
    dialog.cancel();//close the dialog    
    }
   }
 
   private ListView getList(String path){  
    l=new ListView(context); //create new list object
    l.setBackgroundColor(Color.BLACK); //apply background to the ListView
    listFiles(); //add files and directories to the list for the first time
    l.setOnItemClickListener(new ItemList()); //register item click event
    return l;
   }  
 
 
   public void listFiles(){
   
    try{
    File f=new File(path);    
    if(f.isDirectory()){ //Check whether the path is a directory
    String[] contents=f.list();
    if(contents.length>0){ //list contents of the directory
    //ArrayAdapter<String> aa=new ArrayAdapter<String>(context,R.layout.listlayout,contents);
    ListAdapterModel aa=new ListAdapterModel(context,R.layout.listlayout,R.id.label,contents,path);
    l.setAdapter(aa);
    }
    else
    path=f.getParent(); //keep its parent directory for empty sub-directory
    //Toast.makeText(context,att_path, Toast.LENGTH_SHORT).show();
    }
    else if(f.isFile()){ //Otherwise, get the full path of the file and keep parent directories of the file.
    //This file will be attached to the email message
    att_path=f.getPath();
    //path=att_path.substring(0, att_path.lastIndexOf("/"));
    path=f.getParent();
    Toast.makeText(context,att_path, Toast.LENGTH_SHORT).show();
    }
    }catch(Exception e){e.printStackTrace();}  
   }
 
   private class ItemList implements OnItemClickListener{
   
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
     
    l.setSelector(R.drawable.selection_style); //apply background style to the selected item
    ViewGroup vg=(ViewGroup)view;
      String selectedItem = ((TextView) vg.findViewById(R.id.label)).getText().toString();
    path=path+"/"+selectedItem; //append the item to path
           listFiles();  //update files and directories of the list when a file or directory
       
      }
   }
 
   public String getFilePath(){
    if(RESULT==RESULT_OK)
    return att_path;
    else return null;
   }
}


The AndFileChooser class has the show method to display the file chooser dialog. In the show method, the Builder class that is a sub-class of the AlertDialog is used to create a dialog. To add an OK button to the dialog, you can use the setPositiveButton method of the Builder class. You will need to specify the text to display on the button (OK), and the click listener to this method. The OkOnClickListener class defines the click listener for the OK button.

private final class OkOnClickListener implements DialogInterface.OnClickListener {
    public void onClick(DialogInterface dialog, int which) {
       RESULT=RESULT_OK; //set the RESULT to RESULT_OK
       dialog.cancel();//close the dialog
     }
}


The click listener registers the OK button with the click event and performs action when the button is clicked. We also need one more button (Up) to take the user back up one level of the directories structure. The setNeutralButton is called to define this button. In Android, the dialog closes immediately when the user clicks any button on the dialog. However in the File Chooser app, when the user clicks the Up button, the dialog must not close. Instead, it takes the user back up one level. To do what we want, we need to change this default behavior by setting null to its click listener when it is defined and later overriding its setOnClickListener method.

To display the ListView on the dialog, you need to use the setView method of the Builder. In this app, our ListView object is defined in the getList(String path) method. This method returns a ListView object with items. Its items are files and directories of the parent directory specified by the path argument. In the getList method, the listFiles method is called to retrieve the contents (files and directories) of the input path and show them on the list. When the user selects an directory item of the ListView, the contents of the directory will be listed (overriding the previous contents of the ListView). To perform this action, you need to register the ListView with the item click listener by using the setOnItemClickListener method. The ItemList class defines the item click listener for the ListView.

private class ItemList implements OnItemClickListener{

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

    l.setSelector(R.drawable.selection_style); //apply background style to the selected item
    ViewGroup vg=(ViewGroup)view;
    String selectedItem = ((TextView) vg.findViewById(R.id.label)).getText().toString();
    path=path+"/"+selectedItem; //append the item to path
    listFiles(); //update files and directories of the list when a file or directory

    }
}
In the onItemClick method, the selection style is applied to the selected item of the ListView by using the setSelector method. You need to pass the layout that applies the selection style to the selected item (selection_style.xml). When an item of the ListView is selected, you can access this item by using the view argument. As you already know, an item of the ListView contains two parts--image and text. Each part is represented by different component (ImageView and TextView), So you need to cast the view to a ViewGroup object. Within the ViewGroup object, you can refer to any component that it contains.

The path variable is updated to reflect the current path of the selected file or directory. The listFiles method is called again to update the contents of the ListView.
In the listFiles method, a File object is created to point to the current path so you can determine that the current path is directory or file. If it is a directory, its contents will be listed. Otherwise, the current file path is captured and the path variable is updated to its parent directory. The selected path of the file can be accessed by using the getPath method.

In this method, you also see a class called ListAdapterModel. The ListAdapterModel is a class that extends the ArrayAdapter class. As you already know from my previous post (Web Downloader), ArrayAdapter is used as data source of the ListView. If an item of the ListView has only one text component, there is no need to extend the ArrayAdapter. However, in this app, an item of the ListView contains two parts--image and text. So, the ArrayAdapter has to be extended. To enable the item to display both image and text, you need to override the getView method of the ArrayAdapter class. Below is the content of the ListAdapterModel.java file.
compass app flashLight app

ListAdapterModel.java

package com.example.filechooser;
import java.io.File;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class ListAdapterModel extends ArrayAdapter<String>{
int groupid;
String[] names;
Context context;
String path;
public ListAdapterModel(Context context, int vg, int id, String[] names, String parentPath){
super(context,vg, id, names);
this.context=context;
groupid=vg;
this.names=names;
this.path=parentPath;
}
public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View itemView = inflater.inflate(groupid, parent, false);
        ImageView imageView = (ImageView) itemView.findViewById(R.id.icon);
        TextView textView = (TextView) itemView.findViewById(R.id.label);
        String item=names[position];
        textView.setText(item);
        File f=new File(path+"/"+item);
        if(f.isDirectory())
        imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.diricon));
        else
        imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.fileicon));
        return itemView;
     
}

}


Now, you have set up the FileChooser dialog. It is ready to use in your activity. For testing, in the onStart method of the MainActivity class, you can create an instance of the AndFileChooser class and call its show method to display the dialog.

MainActivity.java file

package com.example.filechooser;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

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

    protected void onStart(){
    super.onStart();
    AndFileChooser filechooser=new AndFileChooser("/",this);
    filechooser.show();
   
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
}


Don't forget to run the app, otherwise the file chooser does not display.


FileChooser run on Emulator

Download apk file of the FileChooser app

Merge or Combine PDF, Txt, Images

Wednesday, September 11, 2013

Ideal Body Weight Calculator

In this post, you learn to create the Ideal Body Weight Calculator (IBWC) app. The app allows the user to specify his/her sex and height. Then the recommended weight of the user is calculated. The Devine formula is used to calculate the IBW for men. This formula is shown below.
Ideal Body Weight =50kg+2.3* (height-60)

Another formula used in Ideal Body Weight Calculator app is Robinson formula. This formula is appropriate for women. So, we use this formula to calculate the IBW for women.
Ideal Body Weight=49kg+1.7*(height-60)

It is noted that these formulas are appropriate for people who are taller than 5 feet or 60 inches.

For the user interface, we need two TextView, one CheckBox, one EditText, one Spinner, and one Button. The first TextView displays the question text "Are you male?". Next to this TextView, it is a CheckBox view. The CheckBox displays "Yes" next to the tick mark. The user answers the question by selecting or unselecting the CheckBox. We use this CheckBox to determine the sex of the user.

The EditText view is used to allow height input. This value can be in inch or centimeter. The user can specify the measurement of the height value by choosing in or cm from the Spinner view next to this EditView. The file applies layout to the spinner is called spinner_style.xml. This file locates in res/layout directory. Here is the content of the spinner_style.xml file.

<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
android:singleLine="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee" />

The last TextView is used to display a note to the user regarding the limitation of the two formulas.
The Button view displays the text "Calculate". When the Calculate button is pushed, the calculateIBW method is called to perform the calculation. The android:onClick property links the Button view and the calculateIBW method. This method is defined in the MainActivity.java file. The background of the Button view is defined by a drawable resource that is written in the bt_style.xml file. The bt_style.xml file is stored in res/drawable directory. Here is the content of the bt_style.xml file:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape>
<solid
android:color="#ff00ff" />
<stroke
android:width="1dp"
android:color="#171717" />
<corners
android:radius="3dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
<item>
<shape>
<gradient
android:startColor="#ffffff"
android:endColor="#992211"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#171717" />
<corners
android:radius="4dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
</selector>

Ideal Body Weight Calculator Interface


The activity_main.xml file that is the source for IBWC app user interface can be written as shown below:
<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: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=".MainActivity"
android:orientation="vertical"
android:background="@drawable/bgimage">

<LinearLayout
android:layout_marginTop="20dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<TextView
android:id="@+id/txt_qa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/txt_q"
/>
<CheckBox
android:id="@+id/ch_y"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ch_y"

/>

</LinearLayout>

<LinearLayout
android:layout_marginTop="20dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<EditText
android:id="@+id/txt_height"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/hint_h"
android:inputType="numberDecimal" />
<Spinner
android:id="@+id/unit_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

<LinearLayout
android:layout_marginTop="20dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/bt_calc"
android:background="@drawable/bt_style"
android:text="@string/bt_text"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginRight="20sp"
android:onClick="calculateIBW"
/>
<TextView
android:id="@+id/txt_result"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#992211"
android:textSize="20sp"
/>
</LinearLayout>
<TextView
android:id="@+id/txt_note"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_marginTop="20sp"
android:text="@string/txt_note"
/>
</LinearLayout>

As you have seen in the picture above, the IBWC app has a background image. You can specify the background image of an Android app by using the android:background property of the top LinearLayout. In this app, the image that is used as the background when the activity is active is called bgimage that is stored in the res/drawable directory.
android:background="@drawable/bgimage"

Some string values used in the activity_main.xml are defined in the string.xmlf file. The content of the strings.xml file is shown below.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">IBWCalculator</string>
<string name="action_settings">Settings</string>
<string name="txt_q">Are you male?</string>
<string name="ch_y">Yes</string>
<string name="hint_h">Enter your height</string>
<string name="bt_text">Calculate</string>
<string name="txt_note">Note: This calculation is appropriate for people who are taller than 5 feet or 60 inches.</string>

</resources>

The last important file that you have to look and modify is MainActivity.java file. In this file, you need to add some methods such as setUpSpinnerData, getHeight, calculateIBW, and showAlert.

package com.example.ibwcalculator;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;

public class MainActivity extends Activity {

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public boolean onCreateOptionsMenu(Menu menu) {
        //Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
    public void onStart(){
    super.onStart();
    setUpSpinnerData(); //populate data in spinner view
       
    }


    //This method will be invoked to setup data of the spinner view
    public void setUpSpinnerData(){
    Spinner sp=(Spinner)findViewById(R.id.unit_spinner);
    String[] items={"in","cm"};
    ArrayAdapter<String> aa=new ArrayAdapter<String>(this,R.layout.spinner_style,items);
    sp.setAdapter(aa);
   
    }
 
  //This method returns the height in inch
    public double getHeight(String strvalue){
    Spinner sp=(Spinner)findViewById(R.id.unit_spinner);    
   
    double value=Double.valueOf(strvalue);
    if(sp.getSelectedItem().toString().equals("cm")){
    return(value/2.54); //1inch=2.54cm
   
    }
    else {
    return(value);
    }
    }
   
 
 
    //This method calculates the IBW  
    public void calculateIBW(View view){
    double ibw=0.0f;
    CheckBox ch=(CheckBox)findViewById(R.id.ch_y);
    EditText txth=(EditText)findViewById(R.id.txt_height);
    String strvalue=txth.getText().toString();
    if(strvalue.length()>0){
    double height=getHeight(strvalue);    
    if(ch.isChecked()) //calculate ideal body weight for men
    ibw=50+2.3*(height-60);
    else //calculate ideal body weight for women
    ibw=49+1.7*(height-60);
    //create decimal formatter object to format the result
    NumberFormat nf=new DecimalFormat("###.00");    
    //display the result in txt_result
    TextView txtresult=(TextView)findViewById(R.id.txt_result);    
    txtresult.setText("IBW="+nf.format(ibw)+"kg");
   
    }
   
    else{
    showAlert();
    }
    }
 
 
     //This method will be invoked to display alert dialog
     public void showAlert(){
   
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
         builder.setMessage("Please enter your height!");
         builder.setCancelable(true);
         builder.setPositiveButton("OK", new OkOnClickListener());
         AlertDialog dialog = builder.create();
         dialog.show();
   
     }
     private final class OkOnClickListener implements
     DialogInterface.OnClickListener {
      public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
      }
     }

 
}


The setupSpinnerData is invoked when the app starts to populate entries of the spinner. These entries are in and cm. You specify the entries of the spinner in the ArrayAdapter object then set this object to the Spinner view by using its setAdapter method. When you create ArrayAdapter object from the ArrayAdapter class, you need to provides three values to constructor of the ArrayAdapter class. The first value is the context. You can use this for this value to refer to the current activity. The second value is the layout of the Spinner view. This layout is defined in the spinner_style.xml file as mentioned above. The last value is the array that contains entries of the spinner.
The getHeight method returns the height input in inch. This value will be used in the calculateIBW method to calculate the ideal body weight for the user.
The calculateIBW is invoked when the user pushed the Calculate button. This method calculate the ideal body weight of the user based on his/her sex. If the user is male (CheckBox is selected), the Davine formula is used. Otherwise, the Robinson formula is used.
The showAlert method is invoked to display a dialog to ask the user to enter his/her height in the EditText, txt_height. This alert dialog is displayed only when the user leaves the EditText, txt_height blank and pushes the Calculate button. In Android, the alert dialog box can be created by using the Builder class. This class is a sub-class of the AlertDialog class.

Testing ideal weight calculator

Download apk file of the Ideal Body Weight Calculator app Merge or Combine PDF, Txt, Images