自定义View(二)自定义View的构造方法及自定义属性

       更多内容:

       (一)自定义View的分类点击打开链接
       (二)自定义View的构造方法及自定义属性
       (三)自定义View的常用方法(测量、绘制、位置)
       (四)自定义View的具体实现
       (五)事件分发机制

      

         一、自定义View的构造方法

         无论是继承自View还是ViewGroup的自定义控件,编译器都会提示我们

         Implicit super constructor ViewGroup() is undefined for default constructor. Must define an explicit constructor          

        意思是基类没有无参的构造方法,必须定义一个带参的构造方法。

        我们可以重载下面三个构造方法(API21已经有四个参数的构造方法)。

   public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        
    }

      首先解决两个问题

      一、我们在构造方法中具体做什么

      一般做一些初始化工作,获取自定义属性、获取子View等等,以后的demo中会具体讲解


     二、如何选择构造方法

     关于三个方法的选择,源码的注释里已经写得非常清楚了

    /**
     * Simple constructor to use when creating a view from code.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     */
    public View(Context context) {
                      ……
    }
       带一个参数的构造方法:

       Simple constructor to use when creating a view from code

       当我们在代码里创建一个view时,使用此方法

    /**
     * Constructor that is called when inflating a view from XML. This is called
     * when a view is being constructed from an XML file, supplying attributes
     * that were specified in the XML file. This version uses a default style of
     * 0, so the only attribute values applied are those in the Context's Theme
     * and the given AttributeSet.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @see #View(Context, AttributeSet, int)
     */
    public View(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

         带两个参数的构造方法:

        Constructor that is called when inflating a view from XML. This is called when a view is being constructed from an XML file, supplying attributes   that were specified in the XML file. This version uses a default style of  0, so the only attribute values applied are those in the Context's Theme and the given AttributeSet.

        当我们在xml文件中创建一个控件时,使用此方法。这个方法传递了控件在xml文件中定义的所有属性(包括自定义属性),即attars。它所使用的的默认样式是0,这意味Context和Theme给定的attributeset是唯一用到的属性值。

    /**
     *  Perform inflation from XML and apply a class-specific base style. This
     * constructor of View allows subclasses to use their own base style when
     * they are inflating. For example, a Button class's constructor would call
     * this version of the super class constructor and supply
     * <code>R.attr.buttonStyle</code> for <var>defStyle</var>; this allows
     * the theme's button style to modify all of the base view attributes (in
     * particular its background) as well as the Button class's attributes.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @param defStyleAttr An attribute in the current theme that contains a
     *        reference to a style resource to apply to this view. If 0, no
     *        default style will be applied.
     * @see #View(Context, AttributeSet)
     */
    public View(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context);

      ……
        }

         带三个参数的构造方法:

         Perform inflation from XML and apply a class-specific base style. This constructor of View allows subclasses to use their own base style when
they are inflating. For example, a Button class's constructor would call this version of the super class constructor and supply
R.attr.buttonStyle for defStyle ; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes. 

        在xml创建一个控件并且使用某个特定类型的基础样式时,使用此方法。

        这个方法允许子类在加载时使用它们自己的基础样式。比如说,一个按钮类重载此构造方法时,将要调用基类的同类型构造方法,使用R.attr.buttonStyle作为默认样式。这使得theme的按钮样式修改所有基础控件属性(特别是其背景)以及按钮类的属性。

       这里我们再看一下defStyleAttr参数的解释:

       defStyleAttr: An attribute in the current theme that contains a reference to a style resource to apply to this view. If 0, no default style will be applied.

        当前theme中引用自style的属性,如果是0的话,不使用任何style。

        补充一句:系统不会主动的调用这个方法,需要我们显式的调用,比如:

  public MyView(Context context, AttributeSet attrs) {
        //显式调用三个参数的构造方法 ,将R.attr.buttonStyle作为控件的基础样式
        this(context, attrs, R.attr.buttonStyle);
    }
    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }
        当我们显式的调用这个方法时,我们的自定义控件将使用这个defStyle作为基础的样式,但是这个defStyle所定义的属性是可以被覆盖的。比如我们在自定义控件时在xml文件中重写了defStyle的某些属性,这些属性就被覆盖了。

       这是因为同时定义一个属性时,是有优先级的:xml>style>defStyle>theme


       在实际运用中,为了方便,我们一般会按如下方式同时重载这三个构造方法

   public MyView(Context context) {
		this(context, null);// 调用两个参数的构造方法

	}
	
    public MyView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);//调用三个参数的构造方法

    }
    
    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);//调用基类构造方法

    }


       二、自定义View的自定义属性

         对于一个自定义控件,它拥有基类所有的属性,同时也可以定义自己的属性,这就是自定义属性

       举个最简单的例子,我们现在自义定一个圆形头像,首先让它继承ImageView,这样就拥有了背景这个属性。但是作为一个圆形头像它是需要半径这个属性的,这就需要我们去自定义了。


       ①在res文件的values目录下,创建一个xml文件,我们将在这个文件中编写自义定属性。我创建的是attrs.xml ,名字不是固定的可以自己取。

         

         ② <declare-styleable name="控件名">       
                <attr name="属性名" format="属性类型" /> 

                  ……   
           </declare-styleable>
    

<resources>
    
     <declare-styleable name="CircleIcon">       
        <attr name="circle_radius" format="float" />     
     </declare-styleable> 
    
</resources>
          format选项说明及使用,这篇博客归纳的非常完整Android自定义属性时format选项参数说明及用法

        ③我们怎么得到已经写好的自定义属性呢,还记得刚刚讲过的两个参数的构造方法吗,它的参数 AttributeSet attrs传入了自定义控件的所有属性,包括xml文件里申明的,也包括自定义的,因此我们在两个参数的构造方法中获取自定义属性

 public CircleView(Context context, AttributeSet attrs) {
        this(context, attrs, defStyle);//调用基类构造方法
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.CircleIcon);//  <declare-styleable name="CircleIcon"> 
        float radius = a.getFloat(R.styleable.CircleIcon_circle_radius,//控件名_属性名
                1);
        a.recycle();//一定要写
    }

       当我们获取了自定义属性时,就可以使用它们来构建控件了,具体的内容将在后面的文章详细讲解








    



                 



















      

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页