Feb 26, 2013

Android Chips EditText , Token EditText and Bubble EditText [Part 2]

Since I write first previous blog on Chips Edit Text, many developer ask me to make chips edit text as library so they can integrate easily in the project, so I develop Chips Edit Text as library.

Android Chips EditText , Token EditText and Bubble EditText - [Part 1]




Github url : https://github.com/kpbird/chips-edittext-library

Github as two sub folders namely 1. ChipsEditTextLibrary 2. ChipsEditTextDemo

How to use library ?

Step 1: Clone git repor or download zip file

Step 2: Import ChipsEditTextLibrary in your eclipse workspace

Step 3: Create new Android project

Step 4: Set ChipsEditTextLibrary as reference of your project


Right Click on Project -> Properties -> Android ->Add

Step 4: Open your xml layout file and add ChipsEditText control
 <com.kpbird.chipsedittextlibrary.ChipsMultiAutoCompleteTextview
        android:id="@+id/chipsMultiAutoCompleteTextview1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:ems="10"
        android:text="" >

        <requestFocus />
    </com.kpbird.chipsedittextlibrary.ChipsMultiAutoCompleteTextview>

Step 5: Open your Activity class and write following code. 


package com.kpbird.chipsedittextdemo;

import java.util.ArrayList;
import android.app.Activity;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.util.Log;

import com.kpbird.chipsedittextlibrary.ChipsAdapter;
import com.kpbird.chipsedittextlibrary.ChipsItem;
import com.kpbird.chipsedittextlibrary.ChipsMultiAutoCompleteTextview;

public class MainActivity extends Activity {

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

  ChipsMultiAutoCompleteTextview ch = (ChipsMultiAutoCompleteTextview) findViewById(R.id.chipsMultiAutoCompleteTextview1);

  String[] countries = getResources().getStringArray(R.array.country);
  TypedArray imgs = getResources().obtainTypedArray(R.array.flags);

  ArrayList<ChipsItem> arrCountry = new ArrayList<ChipsItem>();

  for (int i = 0; i < countries.length; i++) {
   arrCountry.add(new ChipsItem(countries[i], imgs
     .getResourceId(i, -1)));
   Log.i("Main Activity", arrCountry.get(i).getTitle() + " = "
     + arrCountry.get(i).getImageid());
  }

  Log.i("MainActivity", "Array :" + arrCountry.size());

  ChipsAdapter chipsAdapter = new ChipsAdapter(this, arrCountry);
  ch.setAdapter(chipsAdapter);

 }

}

Step 6: You need to use ChipsItem and ChipsAdapter to provide data. ChipsItem has two field 1. Title and 2. Image Id (R.drawable.android), In above sample I have created two array in string.xml for title and images.






continue reading Android Chips EditText , Token EditText and Bubble EditText [Part 2]

Feb 22, 2013

Android API document linked with the source code

Hello guys,

I found interesting things today, While reading Android API document,  I found (View Source) link beside class name. Now It is very easy to quick look of class/source code from API document.

Let's check source code of Activity class.

Step 1: Open following link in your browser
http://developer.android.com/reference/android/app/Activity.html



Step 2: Click on View Source link beside Activity

If you don't see View Source link then install "Android SDK Reference Search" Chrome Extension

Step 1: Open following link
https://chrome.google.com/webstore/detail/android-sdk-reference-sea/hgcbffeicehlpmgmnhnkjbjoldkfhoin


Step 2: Click "Add to chrome", after installation open following link to verify extension
chrome://extensions/



continue reading Android API document linked with the source code

Feb 12, 2013

Android Chips EditText , Token EditText and Bubble EditText - [Part 1]

Chips EditText, Token EditText, Bubble EditText, Spannable EditText and etc.. There are many names of this control. Whatever we call it but this control is not available in Android. I found many questions and solutions for this control. 

Few popular questions & solutions 
1] Roman Nurik : https://plus.google.com/113735310430199015092/posts/WUd7GrfZfiZ 
2] Android EditText Gmail like Field : http://stackoverflow.com/questions/13747809/android-edittext-gmail-like-to-field 
3] Android Labels or Bubbles in Edit Text : http://stackoverflow.com/questions/8090711/android-labels-or-bubbles-in-edittext/8128848#8128848 
4] Contact Bubble Edit Text : http://stackoverflow.com/questions/10812316/contact-bubble-edittext 

While I was reading above post, I thought that, I should develop Chips Edit Text control, which should be easy to understand and integrated in project. Here, My control is named as "Chips Edit Text". Before going to technical details, I would like to show few screenshots.

 

 


Step 1: Prerequisite

Android provides bunch of Span classes, Span classes are used to format text. I suggest to read following articles for helpful detail and in-depth understanding.

1] Introduction to Span
http://blog.stylingandroid.com/archives/177

2] Easy Method for Formatting Android
http://www.androidengineer.com/2010/08/easy-method-for-formatting-android.html

3] API Classes : Spannable, SpannableString, SpannableStringBuilder, ImageSpan ,ClickableSpan 

Step 2 : Logic

Our goal is to display background (border & fill with color) and image at right side of every chip. Android spannable classes allow us to set background color only. It does not support any drawable at background. Another problem is right side image. Android has ImageSpan class, we can display image at right side with ImageSpan but problem is that ImageSpan will consider as separate entity and it will display outside of background.

I have implemented following logic to overcome above two problems

1. Extends MultiAutoCompleteTextView to create chips edit text.
2. Generate TextView dynamically in code and set style & drawable at right side.
3. Capture image/bitmap of newly generated TextView.
4. Set ImageSpan instead-of country name. 

  
Step 3 : Create Android Project

Create Android project named "Chips Edit Text" 

Step 4 : Create class named "ChipsMultiAutoCompleteTextview.java"


package com.kpbird.chipsedittext;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.MultiAutoCompleteTextView;
import android.widget.TextView;

public class ChipsMultiAutoCompleteTextview extends MultiAutoCompleteTextView implements OnItemClickListener {

 private final String TAG = "ChipsMultiAutoCompleteTextview";
 
 // Constructor 
 public ChipsMultiAutoCompleteTextview(Context context) {
  super(context);
  init(context);
 }
 // Constructor 
 public ChipsMultiAutoCompleteTextview(Context context, AttributeSet attrs) {
  super(context, attrs);
  init(context);
 }
 // Constructor 
 public ChipsMultiAutoCompleteTextview(Context context, AttributeSet attrs,
   int defStyle) {
  super(context, attrs, defStyle);
  init(context);
 }
 // set listeners for item click and text change 
 public void init(Context context){
  setOnItemClickListener(this);
  addTextChangedListener(textWather);
 }
 // TextWatcher, If user type any country name and press comma then following code will regenerate chips 
 private TextWatcher textWather = new TextWatcher() {
  
  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
   if(count >=1){
    if(s.charAt(start) == ',')
     setChips(); // generate chips
   }
  }
  @Override
  public void beforeTextChanged(CharSequence s, int start, int count,int after) {}
  @Override
  public void afterTextChanged(Editable s) {}
 };
 //This function has whole logic for chips generate
 public void setChips(){
  if(getText().toString().contains(",")) // check comman in string
  {
   
   SpannableStringBuilder ssb = new SpannableStringBuilder(getText());
   // split string wich comma
   String chips[] = getText().toString().trim().split(",");
   int x =0;
   // loop will generate ImageSpan for every country name separated by comma
   for(String c : chips){
    // inflate chips_edittext layout 
    LayoutInflater lf = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    TextView textView = (TextView) lf.inflate(R.layout.chips_edittext, null);
    textView.setText(c); // set text
    setFlags(textView, c); // set flag image
    // capture bitmapt of genreated textview
    int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    textView.measure(spec, spec);
    textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
    Bitmap b = Bitmap.createBitmap(textView.getWidth(), textView.getHeight(),Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(b);
    canvas.translate(-textView.getScrollX(), -textView.getScrollY());
    textView.draw(canvas);
    textView.setDrawingCacheEnabled(true);
    Bitmap cacheBmp = textView.getDrawingCache();
    Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
    textView.destroyDrawingCache();  // destory drawable
    // create bitmap drawable for imagespan
    BitmapDrawable bmpDrawable = new BitmapDrawable(viewBmp);
    bmpDrawable.setBounds(0, 0,bmpDrawable.getIntrinsicWidth(),bmpDrawable.getIntrinsicHeight());
    // create and set imagespan 
    ssb.setSpan(new ImageSpan(bmpDrawable),x ,x + c.length() , Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    x = x+ c.length() +1;
   }
   // set chips span 
   setText(ssb);
   // move cursor to last 
   setSelection(getText().length());
  }
  
  
 }
 @Override
 public void onItemClick(AdapterView parent, View view, int position, long id) {
  setChips(); // call generate chips when user select any item from auto complete
 }
 
 // this method set country flag image in textview's drawable component, this logic is not optimize, you need to change as per your requirement
 public void setFlags(TextView textView,String country){
  country = country.trim();
  if(country.equals("India")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.india, 0);
  }
  else if(country.equals("United States")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.unitedstates, 0);
  }
  else if(country.equals("Canada")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.canada, 0);
  }
  else if(country.equals("Australia")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.australia, 0);
  }
  else if(country.equals("United Kingdom")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.unitedkingdom, 0);
  }
  else if(country.equals("Philippines")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.philippines, 0);
  }
  else if(country.equals("Japan")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.japan, 0);
  }
  else if(country.equals("Italy")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.japan, 0);
  }
  else if(country.equals("Germany")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.germany, 0);
  }
  else if(country.equals("Russia")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.russia, 0);
  }
  else if(country.equals("Malaysia")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.malaysia, 0);
  }
  else if(country.equals("France")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.france, 0);
  }
  else if(country.equals("Sweden")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.sweden, 0);
  }
  else if(country.equals("New Zealand")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.newzealand, 0);
  }
  else if(country.equals("Singapore")){
   textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.singapore, 0);
  }
  
  
 }
 
}

Step 5 : Create drawable shape for chip named "chips_edittext_bg.xml" in drawable folder.


<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >

    <stroke
        android:width="1dp"
        android:color="#A6B0B8" />

    <solid android:color="#E5E5E6" />

    <corners
        android:bottomLeftRadius="3dp"
        android:bottomRightRadius="3dp"
        android:topLeftRadius="3dp"
        android:topRightRadius="3dp" >
    </corners>

</shape>

Step 6 : Create TextView layout for chip named "chips_edittext.xml" in layout folder


 <?xml version="1.0" encoding="UTF-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/edtTxt1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/chips_edittext_gb"
    android:drawablePadding="2dp"
    android:drawableRight="@drawable/android"
    android:padding="8dp"
    android:shadowColor="#FFFFFF"
    android:shadowDy="1"
    android:shadowRadius="0.01"
    android:textColor="#000000"
    android:textSize="18sp"
    android:textStyle="bold" />

Step 7 : Create string array for multi select data named "country" in strings.xml 


    <string-array name="country">
        <item >India</item>
        <item>United States</item>
        <item>Canada</item>
        <item>Australia</item>
        <item>United Kingdom</item>
        <item>Philippines</item>
        <item >Japan</item>
        <item>Italy</item>
        <item>Germany</item>
        <item>Russia</item>
        <item>Malaysia</item>
        <item>France</item>
        <item>Sweden</item>
        <item>New Zealand</item>
        <item>Singapore</item>
    </string-array>

Step 8 : Edit layout of main_activity.xml file


<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" >
    <com.kpbird.chipsedittext.ChipsMultiAutoCompleteTextview
         android:id="@+id/multiAutoCompleteTextView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:ems="10"
         />
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/multiAutoCompleteTextView1"
        android:onClick="buttonClicked"
        android:text="@string/getvalue" />
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/button1"
        android:text="@string/selectedcountries"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

Step 9 : Edit code of mainactivity.java file


package com.kpbird.chipsedittext;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.MultiAutoCompleteTextView;
import android.widget.TextView;

public class MainActivity extends Activity {

 ChipsMultiAutoCompleteTextview mu;

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

  mu = (ChipsMultiAutoCompleteTextview) findViewById(R.id.multiAutoCompleteTextView1);

  String[] item = getResources().getStringArray(R.array.country);

  Log.i("", "Country Count : " + item.length);
  mu.setAdapter(new ArrayAdapter(this,
    android.R.layout.simple_dropdown_item_1line, item));
  mu.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
 }

 public void buttonClicked(View v) {
  TextView tv = (TextView) findViewById(R.id.textView1);
  tv.setText(mu.getText().toString());
 }

}





Source code : Github Link
    

continue reading Android Chips EditText , Token EditText and Bubble EditText - [Part 1]