Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Bar Chart with Click Listener in Android

4.10/5 (6 votes)
20 Apr 2015CPOL1 min read 17.3K  
Show an option when a selected bar chart is clicked in from screen.

Introduction

Agree, most of us use Android smartphones and some of us love coding. In this tip, I will share my concept on how to capture click event in Android in a specific chart created in canvas in Android. I've searched from the internet and most of the discussion is on how to create a bar chart with no specific function but a chart only. So, when I looked at the Android developer site, I started developing a custom gradient bar chart with click event capture. Upon learning about the output, it was good and looks to be functional.

So without much further ado, let's proceed with the Java coding...

Background

To be able to comprehend the Android Programming, you must have installed an Android Studio or equivalent. The IDE installer can be found here. Initially, it will be tough and challenging but over the course of time, it will become simpler and easier to do.

Using the Code

First, you should create a public class and extend it to View. Then create an override for onDraw, onSizeChanged, onTouchListener and onDraw respectively.

Java
package com.emer.myApp;

/*Auto imports necessary infos*/
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;

/*Create a public class and extends to view */
public class StatisticGraph extends View{
    
    private Paint paint;
    private List<String> _name = new ArrayList<>();
    private List<Float> _value = new ArrayList<>();
    List<String> _position = new ArrayList<>();
    private String title;
    
    private List<Rect> mRect; /*Use for bar chart screen position*/
    private Context mContext;
    private int mViewH;
    private int mViewW;

    GradientDrawable gradientDrawable; /*Include gradient effect in chart*/
    Rect rect;

Below is the default override called when a view is first created.

Java
 public StatisticGraph(Context context, List<Float> _value, String title,
                          List<String> _name,List<String>position) {
    super(context);
    mContext=context;

    rect = new Rect();
    mRect = new ArrayList<>();
    gradientDrawable= new GradientDrawable();

    this._value = _value;
    this.title = title;
    this._name = _name

    this._position = position;
    paint = new Paint(); 

    /* change the font of the paint characters*/
    Typeface tf = Typeface.createFromAsset(context.getAssets(),
                FontService.getFontPath(Enums.Font.Regular));
    paint.setTypeface(tf);
}

 /*get the maximum value from the newly xfered data*/
 private float getMax() {
        float L = Integer.MIN_VALUE;
        for(Float f:_value){
             if(f>L) L=f;
        }
        return L + (L/2);
 }

Below is the code to capture touch event in Android.

Java
/*capture touch event*/
@Override
    public boolean onFilterTouchEventForSecurity(MotionEvent event) {
        float x = event.getX();
        //float y = event.getY();
        switch(event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                int i=0;
                for(Rect r:mRect){
                    /*Log.e("RES", "X: " + x + 
                    " Y: " + y + "Left: " + r.left + " Width:"
                    + r.width() + "height: " + r.height() + 
                    "right: "+ r.right + " bottom: " + r.bottom
                    +" top: " + r.top);*/
                    if(((x>r.left) && x< (r.left+ r.width()))
                            )//&& (y>r.bottom && y<r.top))
                    {
                        String name =_name.get(i);
                        /*get the string value of _values rounded off to nearest value*/
                        String voteCount = String.valueOf(Math.round(_value.get(i)));
                        if (Storage.isFileExist(mContext, name))
                        {
                            Object o = Storage.getImage(mContext, name);
                            LayoutInflater layoutInflater = LayoutInflater.from(mContext);
                            View view = layoutInflater.inflate(R.layout.popup_image, null);
                            AlertDialog.Builder alertMessage = new AlertDialog.Builder(mContext);
                            TextView textView = (TextView)view.findViewById(R.id.popup_title);
                            Typeface tf = Typeface.createFromAsset(mContext.getAssets(),
                                    FontService.getFontPath(Enums.Font.Regular));
                            textView.setTypeface(tf);
                            textView.setText(name + "\nVotes: " + voteCount);
                            ImageView  image = (ImageView) view.findViewById(R.id.image_pop);
                            alertMessage.setCancelable(true);
                            alertMessage.setView(view);
                            if(o!=null){
                                try{
                                    image.setImageBitmap((Bitmap)o);
                                }catch (NullPointerException e){
                                    image.setImageBitmap(BitmapHelper.getBitmap(mContext,
                                            R.drawable.no_picture));
                                }
                            }else{
                                image.setImageBitmap(BitmapHelper.getBitmap(mContext,
                                        R.drawable.no_picture));
                            }
                            AlertDialog alertDialog = alertMessage.create();
                            alertDialog.show();
                        }
                        break;
                    }
                    i++;
                }
                break;
        }
        return super.onFilterTouchEventForSecurity(event);
    }

Below is the code to capture the size of Android. It differs from every phone maker so be sure to include this parameter to measure the position of bar chart.

Java
@Override
   protected void onSizeChanged(int w, int h, int oldw, int oldh) {
       super.onSizeChanged(w, h, oldw, oldh);
       mViewH =h;
       mViewW=w;
   }

/* get text size*/
int TextSize(Paint p,String text,float textSize){
       float size;
       if(mViewH<540){//small size
           p.setTextSize(textSize);
           Rect rect =new Rect();
           p.getTextBounds(text, 0, text.length(), rect);
           size = ((textSize * ((float)mViewW)/(float)mViewH) / 2);
           p.setTextSize(size);
       }else{
           float f =(mViewW/mViewH);
           size =textSize * f;
           p.setTextSize(size);
       }
       return  (int)size;
   }

  /*Provide radius to drawable bar chart*/
  void setRadius(GradientDrawable d, float r0,
                               float r1, float r2, float r3) {
      d.setCornerRadii(new float[]{r0, r0, r1, r1,
               r2, r2, r3, r3});
   }

Here's the onDraw code:

Java
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onDraw(Canvas canvas) {
        float _hgt = get_hgt();
        float _wdth = get_wdth() - 1;
        float _max = getMax();
        float cBorder = 15f;
        float _hRef = cBorder * 2;
        float graph_hgt = _hgt - (2 * cBorder);
        float graph_wdth = _wdth - (2 * cBorder);
        paint.setAntiAlias(true);
        paint.setColor(Color.BLUE);
        int sz = TextSize(paint,"3.] PRES GRAPH",15f);
        paint.setTextAlign(Paint.Align.LEFT);
        canvas.drawText("1.] PRES GRAPH",10,sz*2+(cBorder*2),paint);
        canvas.drawText("2.] VPRES GRAPH",10,sz*3+(cBorder*2),paint);
        canvas.drawText("3.] SEN GRAPH", 10, sz * 4 + (cBorder * 2), paint);
        paint.setTextAlign(Paint.Align.CENTER);
        paint.setFakeBoldText(true);
        paint.setColor(Color.BLACK);
        TextSize(paint, title, 30f);
        if ((_max)>-1) {
            canvas.drawText(title, (graph_wdth / 2) + _hRef, cBorder*2, paint);
            float column_wdth = (_wdth - (2 * cBorder)) / _value.size();
            _hRef=_hRef/2;
            int length =_value.size();
            for (int i = 0; i < length ; i++) {
                float val = _value.get(i);
                float rat = val / _max;
                float h = graph_hgt * rat;
                float r = 3;//radius
                paint.setDither(true);
                paint.isAntiAlias();
                rect.left =(int)((i * column_wdth) + _hRef+3);
                rect.top =(int) ((cBorder - h)
                        + graph_hgt);
                rect.right =(int)(((i * column_wdth) + _hRef)
                        + (column_wdth - 1));
                rect.bottom =(int)(_hgt - (cBorder - 1));
                mRect.add(new Rect(rect));/*Add bar char position to list*/
                canvas.save();
                switch(_position.get(i)){
                    case "PRES":
                        gradientDrawable.setOrientation(gradientDrawable.Orientation.LEFT_RIGHT);
                        gradientDrawable.setColors(new int[]{0xFF6762b2, 0xFFfff5fb, 0xFF6762b2});
                        gradientDrawable.setcBorderounds(rect);
                        gradientDrawable.setGradientType(gradientDrawable.LINEAR_GRADIENT);
                        setRadius(gradientDrawable, r, r, 0, 0);
                        gradientDrawable.draw(canvas);
                        paint.setColor(Color.BLACK);
                        break;
                    case "VPRES":
                        gradientDrawable.setOrientation(gradientDrawable.Orientation.LEFT_RIGHT);
                        gradientDrawable.setColors(new int[] { 0xFF25b235,0xFFfff5fb, 0xFF25b235 });
                        gradientDrawable.setcBorderounds(rect);
                        gradientDrawable.setGradientType(gradientDrawable.LINEAR_GRADIENT);
                        setRadius(gradientDrawable, r, r, 0, 0);
                        gradientDrawable.draw(canvas);
                        paint.setColor(Color.BLACK);
                        break;
                    case "SEN":
                        gradientDrawable.setOrientation(gradientDrawable.Orientation.LEFT_RIGHT);
                        gradientDrawable.setColors(new int[] { 0xFFba255b,0xFFfff5fb, 0xFFba255b });
                        gradientDrawable.setcBorderounds(rect);
                        gradientDrawable.setGradientType(gradientDrawable.LINEAR_GRADIENT);
                        setRadius(gradientDrawable, r, r, 0, 0);
                        gradientDrawable.draw(canvas);
                        paint.setColor(Color.BLACK);
                        break;
                }
                canvas.restore();
                paint.setColor(Color.BLACK);
                /*This put a horizontal text to bar chart*/
                /*You can create your own custom design with this code.*/
                String s =_name.get(i);
                sz = TextSize(paint,s,15f);
                float y=(int) (((cBorder*2) - h)
                        + graph_hgt);
                for(char c: _name.get(i).split(" ")[0].toCharArray()) {
                    canvas.drawText(String.valueOf(c),
                            (i * column_wdth)+(_hRef+ cBorder)
                            ,
                            y
                            ,paint);
                    y += sz;
                }
                s =String.valueOf(Math.round(_value.get(i)));
                paint.setColor(Color.BLUE);
                TextSize(paint,s,15f);
                canvas.drawText(s, (i * column_wdth) + _hRef + cBorder
                        ,
                        graph_hgt + (cBorder-h)-5,paint);
            }
        }else{
            paint.setColor(Color.RED);
            canvas.drawText("NO_DATA_RETRIEVED", (graph_wdth / 2) + _hRef, graph_hgt/2, paint);
        }
        super.onDraw(canvas);
    }
}

Points of Interest

This code is used in my current Android app. You should have familiarity in JAVA to understand the code better. If you have any further suggestions, you can post a comment below. Thanks.

History

  • Initial release (Bar chart with gradient design)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)