Monday 8 May 2017

Making custom View in Android

Custom Views is something that makes the look and feel of application more good. This is a field in which I started my research recently to get better hold in it. So here we have got a multi color custom view . With the help of this tutorial , you can get the complete ides of how to make a custom view like pie chart , donut view, raindow etc.
Its really fun when you understand something so easily , that you thought earlier to be very tough .

Lets begin ..

To start with we need to have a custom style declared in the attributes . For this we make a new file in the values folder named "attrs.xml".
   

<?xml version="1.0" encoding="utf-8"?><resources>
    <declare-styleable name="CustomMultiColorView">
        <attr name="radius" format="dimension"/>
    </declare-styleable>
</resources>


For implementing the custom view we need to have a class extending the View class and overriding the onDraw() of it to draw the actual view .In this custom class, we need to have one of the constructor from the View class to make the initialisation of the default values.

The class is named CustomMultiColorView.java  and looks like this :

public class CustomMultiColorView extends View {

    public CustomMultiColorView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
@Overrideprotected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
}
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

  }

In this class,  the default constructor is taken with two arguments. The AttributeSet will help us to fetch the defaults and the structure from the attrs.xml. The paint object is initialised with the deaults in here too to perform the actual drawing on the canvas . The constructor definition looks some what like this :

public CustomMultiColorView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CustomMultiColorView);
    try {
        radius = typedArray.getDimension(R.styleable.CustomMultiColorView_radius, 20.0f);
    } finally {
        typedArray.recycle();
    }
    paint = new Paint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(radius/13.0f);
    paint.setAntiAlias(true);// for crisper edges
    outerCircle = new RectF(); // for making the outer circle 
    innerCircle = new RectF();  // for making the inner circle
}

Now the main part , the drawing of the object . Since we will be providing shadow to the object so we need to initialise the setShadowLayer for the paint object .
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    paint.setShader(null); //pass null to clear any previous color or shader    float adjust = (0.0095f*radius);
    paint.setShadowLayer(8,adjust,-adjust,0xaa000000);

    setLayerType(LAYER_TYPE_SOFTWARE, paint);
    //this makes a space for the outer circle with some padding from the border    
    // in that area we display the shadow, to avoid the circle to look cut opn edges    adjust= (0.076f* radius);
    outerCircle.set(adjust, adjust , radius*2 - adjust, radius*2 -adjust);
    adjust= (0.076f* radius);
    innerCircle.set(adjust, adjust , radius*2 - adjust, radius*2 -adjust);

    setGradient(0xff84BC3D,0xff5B8829);
    drawCircle(canvas,paint,0,60);

    setGradient(0xffe04a2f,0xffB7161B);
    drawCircle(canvas,paint,60,60);

    setGradient(0xff4AB6C1,0xff2182AD);
    drawCircle(canvas,paint,120,60);

    setGradient(0xffFFFF00,0xfffed325);
    drawCircle(canvas,paint,180,60);

    setGradient(0xffe04a2f,0xffB7161B);
    drawCircle(canvas,paint,240,60);
    
    setGradient(0xff4AB6C1,0xff2182AD);
    drawCircle(canvas,paint,300,60);
}

private void setGradient(int i, int i1) {
    paint.setShader(new RadialGradient(radius,radius,radius-10, i,i1, Shader.TileMode.CLAMP));
}

private void drawCircle(Canvas canvas, Paint paint, int i, float v) {
    canvas.drawArc(outerCircle,i,v,false,paint);
}
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int desiredHeight = (int)radius*2;
    int desiredWidth = (int)radius*2;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width ; int height;

    if(widthMode ==MeasureSpec.EXACTLY)
        width = widthSize;
    else if(widthMode == MeasureSpec.AT_MOST)
        width = Math.min(desiredWidth,widthSize);
    else        width = desiredWidth;
    if(heightMode ==MeasureSpec.EXACTLY)
        height = heightSize;
    else if(heightMode == MeasureSpec.AT_MOST)
        height = Math.min(desiredHeight, heightSize);
    else        height = desiredHeight;

    //MUST CALL THIS TO SET THE FINAL DIMENSIONS    setMeasuredDimension(width,height);

}

The xml looks something like this :


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
xmlns:app="http://schemas.android.com/apk/res-auto"    
xmlns:customViews ="http://schemas.android.com/apk/res/sample.com.customviewtutorial"    
xmlns:tools="http://schemas.android.com/tools"    
android:layout_width="match_parent"    
android:layout_height="match_parent"    
android:orientation="vertical"    
tools:context="sample.com.customviewtutorial.MainActivity">
    
    <sample.com.customviewtutorial.DonutView        
android:id="@+id/circle_view"        
android:layout_width="wrap_content"        
android:layout_height="wrap_content"        
android:layout_gravity="center"        
customViews:radius = "90dp"/>
</LinearLayout>


The resultant to this is a view that looks something like this




As you can see we have multi colored circle with shadow for each color beside it inwards and outwards.
The angle sent in the setGradient() set the gradient color and the drawCircle() functions marks the drawing of the arc from and to the angle entered .


Stay tuned with us .. In next tutorial I will write on how to rotate this .

No comments:

Post a Comment

Localization implementation in android apps

The Language translation for the android apps to support the Localization. In android apps, if you want to support multiple languages ...