如何创建自定义视图

时间:2014-03-13 00:42:21

标签: android view android-custom-view custom-view

您好,如何为我的应用创建自定义视图?观察谷歌的例子,但无法做到正确...如果有人知道关于这个主题的任何教程我感谢!晚安!

1 个答案:

答案 0 :(得分:0)

创建View的子类。实现三个View构造函数。实施 onSizeChanged() onDraw()。可选择实施 onMeasure() onLayout() onTouchEvent(),等等。

确实,您最好的方法是从骨架模板开始并扩展它。这就是我经常做的事情:

/**
 * $Id: custom.hlp,v 1.15 2013-10-24 23:20:01 falk Exp $
 *
 * Template.java - Template widget
 *
 * Author: Edward A. Falk
 *         efalk@users.sourceforge.net
 *
 * 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)
    {
    }
}

您甚至可以定义和实现自定义属性,但它很复杂,我建议不要使用它。