Custom View

In some apps though we need to be able to customize views to suit our own needs. This might mean extending an existing view.

The Android framework provides several default views. The base class a view is the View. Views are responsible for measuring, layouting and drawing themselves and their child elements (in case of a ViewGroup). Views are also responsible for saving their UI state and handling touch events. Developers can also create custom views and use them in their application.


Creating custom views is centered around five primary aspects that we may need to control or modify:

  • Control the rendering of the view on screen visually by overriding the onDraw() method.
  • Control the ways the user can interact with the view with the onTouchEvent() and gestures.
  • Control the content dimensions of the view on screen by overriding the onMeasure() method.
  • Defining custom XML attributes for your view and using them to control behavior with TypedArray
  • Storing and restoring state on configuration changes to avoid losing the state with onSaveInstanceState() and onRestoreInstanceState()

So let's create a project where we can understand how CustomView works. We will create switch button here as a CustomView. First of all create a class SwitchButton and extends with View and override onDraw() method and create constructor as below:

Custom SwitchButton Example
public class SwitchButton extends View {
    private boolean on;

    public SwitchButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            paint.setColor(Color.BLUE);
            canvas.drawRoundRect(0, 0, getWidth(), getHeight(), 10, 10, paint);

            paint.setColor(Color.WHITE);
            canvas.drawRoundRect(5, 5, getWidth() - 5, getHeight() - 5, 10, 10, paint);
        } else {
            paint.setColor(Color.BLUE);
            canvas.drawRect(0, 0, getWidth(), getHeight(), paint);

            paint.setColor(Color.WHITE);
            canvas.drawRect(5, 5, getWidth() - 5, getHeight() - 5, paint);
        }

        int radius = ((getHeight() - 10) >> 1) - 20;
        if (!on) {
            paint.setColor(Color.RED);
            canvas.drawCircle(getWidth() - radius - 10, getHeight() >> 1, radius, paint);
        } else {
            paint.setColor(Color.GREEN);
            canvas.drawCircle(radius + 10, getHeight() >> 1, radius, paint);
        }
    }
}

In onDraw() method we can draw Bitmap, circle and text what you what. Now as we created CustomView we need some action on it, either touch or clicked. We implement both touch as well as Click.

First we will show you OnTouchListner:

public class SwitchButton extends View implements View.OnTouchListener {
    private boolean on;

    public SwitchButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        setOnTouchListener(this);
    }

    ....

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        int left = (int) motionEvent.getX();
        int top = (int) motionEvent.getY();

        if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
            Toast.makeText(getContext(), "OnTouchEvent Clicked on left: " + left + ", top: " + top + " of SwitchButton", Toast.LENGTH_SHORT).show();
            return true;
        }
        return false;
    }


Now we will show you how to implement OnClickListner:

Example:
public class SwitchButton1 extends View implements View.OnClickListener {
    private boolean on;

    public SwitchButton1(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        setOnClickListener(this);
    }

   ...

    @Override
    public void onClick(View view) {
         Toast.makeText(getContext(), "OnClickListner action on SwitchButton", Toast.LENGTH_SHORT).show();
    }

Now there is an important method, where you need to set height and width programatically, you can do so, by override a method onMeasure() as:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    // these width and height would be on your calculation
    setMeasuredDimension(220, 110);
}


Below are complete CustomView Class below:

Example:
package com.theitbulls.customviewex;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.Nullable;

public class SwitchButton extends View implements View.OnTouchListener {
    private boolean on;

    public SwitchButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        setOnTouchListener(this);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            paint.setColor(Color.BLUE);
            canvas.drawRoundRect(0, 0, getWidth(), getHeight(), 10, 10, paint);

            paint.setColor(Color.WHITE);
            canvas.drawRoundRect(5, 5, getWidth() - 5, getHeight() - 5, 10, 10, paint);
        } else {
            paint.setColor(Color.BLUE);
            canvas.drawRect(0, 0, getWidth(), getHeight(), paint);

            paint.setColor(Color.WHITE);
            canvas.drawRect(5, 5, getWidth() - 5, getHeight() - 5, paint);
        }

        int radius = ((getHeight() - 10) >> 1) - 20;
        if (!on) {
            paint.setColor(Color.RED);
            canvas.drawCircle(getWidth() - radius - 10, getHeight() >> 1, radius, paint);
        } else {
            paint.setColor(Color.GREEN);
            canvas.drawCircle(radius + 10, getHeight() >> 1, radius, paint);
        }
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        int left = (int) motionEvent.getX();
        int top = (int) motionEvent.getY();

        if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
            on = !on;
            postInvalidate();

            Toast.makeText(getContext(), "OnTouchEvent Clicked on left: " + left + ", top: " + top + " of SwitchButton", Toast.LENGTH_SHORT).show();
            return true;
        }
        return false;
    }
}


Download: You can download complete CustomView Example