android 之 custom view(一)


android在两个基本布局类View和ViewGroup的基础上提供了成熟而又强大的构建UI组件模型。首先,平台包含了各种预先构建的View和ViewGroup,他们被称为widget和布局。你可以用他们构建你的UI。

  一些可用的widget包括Button,TextView,EditText,ListView,CheckBox,RadioButton,Gallery,Spiner,和更多特殊用户的AutoComploteTextView,ImageSwitcher,TextSwitcher.

  一些可以使用的布局如LinearLayout,FramwLayout,RelativeLayout等。

  如果已有的widgets和布局不能满足你的要求,你可以创建你自己的View子类。如果你仅仅需要对一些已存在的widget所一些小小的调整,你可以创建他们的子类来重写一些方法。

  创建你自己的View的子类可以精确地控制界面元素的外观和功能。对于自定义的View组件,通常有下面几种处理方式:

  1.你可以创建一个完全自定义渲染的view类型,例如‘音量控制’旋钮使用2D图形,它类似于一个模拟电子控制。

  2.你可以组合一组view组件来构成一个新的、单一的组件。也许类似一个ComboBox(弹出列表和自由文本字段的组合),双窗口的控制选择器(),以此类推。

  3.你可以采用一种方式,类似覆盖EditText组件展示在屏幕上(记事本教程使用它效果不错,创建了一个具有线条的页面)。

  4.你可以捕获其他的像按键事件和按照自定义的方式处理他们(事件)。

  下面就说说如何创建自定义视图和应用程序中使用它们。一些常用的基本做法:

  1.扩展已有View的class或者View的子类。

  2.覆盖重写父类的一些方法,这些方法通常是以‘on'开头的方法。比如:onDraw,onMeasure(),onKeyDown,等。

  3.使用你的新的扩展类。一旦完成,你的新的扩展类可以使用在代替你扩展类的基类的地方。

  提示:扩展类通常作为使用它们的活动内的内部类,这样父类可以方方便的控制他。为了扩展它的使用范围,你同样可以设置它为public.

完全自定义组件:
  完全自定义组件可以创建你想要的任何图形组件。你可以根据你的想象(组件屏幕尺寸,组件的处理能力)创建你任何喜欢的(组件的)外观和行为。

创建一个完全自定义的组件步骤:

  a.继承View类;b.你可以提供一个构造方法,这个构造方法可以从XML文件获得组件的属性和参数。你可以定义你组件的属性和参数;c.你可以为你的组件创建自己的事件监听器,属性访问与修改,甚至更富在的组件行为;d.下面这个就比较重要了。你可以覆盖重写onMeasure(),onDraw()。默认情况下:onDraw()什么也不做,onMeasure()会设置一个100*100的尺寸。e.你或许需要覆盖重写View其他的方法或者定义你自己的方法。

  

  掌握完全自定义组件最重要的两点:首先你了解组件被显示出来的所走的流程,也就是View类哪些方法被调用。其次就是属性与参数的定义。下图我自认为很重要,要好好理解:

 

上面方法重要的两个:onDraw,onMeasure。那就好好说说他们吧。onDraw()方法传递了一个Canvas对象,这个对象你可以实现任何你想要的:2D图形,其他标准或者自定义的组件,文本风格,或者你其它你想要的(注意:这个并不适应3D图形。如果那样,你必须继承SurfaceView,在一个独立的线程绘画,参考GLSurfaceViewActivity sample).
   onMeasure就复杂了,简单的说就是决定你组件size的地方。这个决定的size不光可以是你组件本身size,还包括孩子组件的size(这个是很多人忽略的问题)。它有两个参数,这个两个参数是跟你的组件的layout_width与layout_height有关系。在你计算出你的组件size之后,你就可以使用setMeasuredDimension()就ok了。为什么呢,其实view的调用程序也就是:measure->onMeasure->setMeasuredDimension.
   下面就说说一些简单的例子吧:
  首先第一个就是samples里面的例子,因为是官方的,这个 必须说说,源代码如下:
  LabelView.java
/**
 * Example of how to write a custom subclass of View. LabelView
 * is used to draw simple text views. Note that it does not handle
 * styled text or right-to-left writing systems.
 *
 */
public class LabelView extends View {
    private Paint mTextPaint;
    private String mText;
    private int mAscent;
   
    /**
     * Constructor.  This version is only needed if you will be instantiating
     * the object manually (not from a layout XML file).
     * @param context
     */
    public LabelView(Context context) {
        super(context);
        initLabelView();
    }

    /**
     * Construct object, initializing with any attributes we understand from a
     * layout file. These attributes are defined in
     * SDK/assets/res/any/classes.xml.
     *
     * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
     */
    public LabelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initLabelView();

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.LabelView);

        CharSequence s = a.getString(R.styleable.LabelView_text);
        if (s != null) {
            setText(s.toString());
        }

        // Retrieve the color(s) to be used for this view and apply them.
        // Note, if you only care about supporting a single color, that you
        // can instead call a.getColor() and pass that to setTextColor().
        setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));

        int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
        if (textSize > 0) {
            setTextSize(textSize);
        }

        a.recycle();
    }

    private final void initLabelView() {
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(16);
        mTextPaint.setColor(0xFF000000);
        setPadding(3, 3, 3, 3);
    }

    /**
     * Sets the text to display in this label
     * @param text The text to display. This will be drawn as one line.
     */
    public void setText(String text) {
        mText = text;
        requestLayout();
        invalidate();
    }

    /**
     * Sets the text size for this label
     * @param size Font size
     */
    public void setTextSize(int size) {
        mTextPaint.setTextSize(size);
        requestLayout();
        invalidate();
    }

    /**
     * Sets the text color for this label.
     * @param color ARGB value for the text
     */
    public void setTextColor(int color) {
        mTextPaint.setColor(color);
        invalidate();
    }

    /**
     * @see android.view.View#measure(int, int)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec),
                measureHeight(heightMeasureSpec));
    }

    /**
     * Determines the width of this view
     * @param measureSpec A measureSpec packed into an int
     * @return The width of the view, honoring constraints from measureSpec
     */
    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the text
            result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
                    + getPaddingRight();
            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(result, specSize);
            }
        }

        return result;
    }

    /**
     * Determines the height of this view
     * @param measureSpec A measureSpec packed into an int
     * @return The height of the view, honoring constraints from measureSpec
     */
    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        mAscent = (int) mTextPaint.ascent();
        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the text (beware: ascent is a negative number)
            result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
                    + getPaddingBottom();
            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    /**
     * Render the text
     *
     * @see android.view.View#onDraw(android.graphics.Canvas)
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
    }
}

  attrs.xml
17 <resources>
18     <!-- These are the attributes that we want to retrieve from the theme
19          in app/PreferencesFromCode.java -->
30      <declare-styleable name="LabelView">
31         <attr name="text" format="string" />
32         <attr name="textColor" format="color" />
33         <attr name="textSize" format="dimension" />
34     </declare-styleable>
35 </resources>
复制代码
  这里它自定义了一个View组建LabelView.它只有三个属性:text,textColor,textSize,及相关方法。在第二个构造函数里,获取xml属性值做一些处理。然后就是onMeasure,onDraw,这个两个没有什么好说的,上面讲了的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值