Search code examples
androidviewandroid-custom-viewcustom-view

How to create Custom Views


Hello, how can I create a custom view for my app? Observed examples of Google, but could not get it right ... if anyone know any tutorial on this subject I thank! Good night!


Solution

  • Make a subclass of View. Implement the three View constructors. Implement onSizeChanged() and onDraw(). Optionally implement onMeasure(), onLayout(), onTouchEvent(), and so forth.

    Truly, your best approach is to start with a skeletal template and expand it. That's what I always do:

    /**
     * $Id: custom.hlp,v 1.15 2013-10-24 23:20:01 falk Exp $
     *
     * Template.java - Template widget
     *
     * Author: Edward A. Falk
     *         [email protected]
     *
     * Date: May 2009
     *
     * This code demonstrates the creation of a custom widget,
     * with some custom resources.
     *
     * Copy and paste this to your own class.
     * Delete the parts you don't need.
     */
    
    package com.example.template;
    
    import android.view.View;
    import android.content.Context;
    import android.content.res.Resources;
    import android.util.AttributeSet;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    
    import android.util.Log;
    
    public class Template extends View {
    
        private static final String TAG = "Template";
        private Context ctx;
        private Resources res;
        private Paint paint;
    
        // Some XML resources:
        private int function;
        private String label;
    
        /**
         * Constructor used when view is constructed in code.
         */
        public Template(Context ctx) {
            super(ctx);
            TemplateInit(ctx, null);
        }
    
        /**
         * Constructor used when view is constructed from XML
         */
        public Template(Context ctx, AttributeSet attrs) {
            super(ctx, attrs);
            TemplateInit(ctx, attrs);
        }
    
        /**
         * Same, with class-specific base style
         */
        public Template(Context ctx, AttributeSet attrs, int defStyle) {
            super(ctx, attrs, defStyle);
            TemplateInit(ctx, attrs);
        }
    
        private void TemplateInit(Context ctx, AttributeSet attrs)
        {
            // Handle whatever common initialization is appropriate for
            // this widget.
            this.ctx = ctx;
            res = getResources();
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setDither(false);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int ow, int oh)
        {
            // Deal with size change
        }
    
        @Override
        protected void onDraw(Canvas canvas)
        {
            super.onDraw(canvas);
    
            paint.setColor(Color.BLACK);
            canvas.drawText(label, x, y, paint);
        }
    
        /**
         * Receive touch events. Leave this out if the default
         * behavior is ok.
         */
        @Override
        public final boolean onTouchEvent(MotionEvent event) {
            // Return false to let some other view have it
            // Return true to say we handled it
            // Or let the superclass deal with it
            return super.onTouchEvent(event);
        }
    
        /**
         * Determine how large we want to be.  We can skip implementing
         * this method if the superclass will handle it for us.
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            int wid = View.MeasureSpec.getSize(widthMeasureSpec);
            int hgt = View.MeasureSpec.getSize(heightMeasureSpec);
            int wmode = View.MeasureSpec.getMode(widthMeasureSpec);
            int hmode = View.MeasureSpec.getMode(heightMeasureSpec);
            final int hpad = getPaddingLeft() + getPaddingRight();
            final int vpad = getPaddingTop() + getPaddingBottom();
    
            // Overview:  Measure our contents plus internal padding.
            // Pass this information to setMeasuredDimensions().  Whatever
            // values we pass, we can assume that's what our final size
            // will be.  If the parent doesn't like it, it will call this
            // method again, with more restrictions.
    
            // What happens now depends on the measure spec mode.  If
            // it's EXACTLY, we ignore our own needs and return the
            // size part of the measurespec.  If the mode is UNSPECIFIED,
            // we ignore the size part of the measurespec and return
            // anything we want.  If the mode is AT_MOST, we might return
            // the lesser of our own needs and the size part of
            // measurespec, or we might just treat this the same
            // as EXACTLY.
    
            // Easiest implementation is to use setMinimumWidth()/Height()
            // to establish our minimum required size, and then let
            // getSuggestedMinimumWidth()/Height() and getDefaultSize()
            // do the heavy lifting.  These may be overridden if needed,
            // to customize behavior.
    
            setMinimumWidth(hpad + yaddayadda);
            setMinimumHeight(vpad + yaddayadda);
            setMeasuredDimension(
              getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
              getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
        }
    
        /**
         * Parent has made final decision and is laying us out.  Here
         * is where we do any internal layout we need.
         */
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b)
        {
        }
    }
    

    You can even define and implement custom attributes, but it's complicated and I recommend against it.