Android自定义View(二、深入解析自定义属性)_第1页
Android自定义View(二、深入解析自定义属性)_第2页
Android自定义View(二、深入解析自定义属性)_第3页
Android自定义View(二、深入解析自定义属性)_第4页
Android自定义View(二、深入解析自定义属性)_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android自定义View(二、深入解析自定义属性)1.为什么要自定义属性  要使用属性,首先这个属性应该存在,所以如果我们要使用自己的属性,必须要先把他定义出来才能使用。但我们平时在写布局文件的时候好像没有自己定义属性,但我们照样可以用很多属性,这是为什么?我想大家应该都知道:系统定义好的属性我们就可以拿来用呗,但是你们知道系统定义了哪些属性吗?哪些属性是我们自定义控件可以直接使用的,哪些不能使用?什么样的属性我们能使用?这些问题我想大家不一定都弄得清除,下面我们去一一解开这些谜团。  系统定义的所有属性我们可以在\sdk\platforms\Android-xx\data\res\values目录下找到attrs.xml这个文件,这就是系统自带的所有属性,打开看看一些比较熟悉的:<declare-styleablename="View"><attrname="id"format="reference"/><attrname="background"format="reference|color"/><attrname="padding"format="dimension"/>...<attrname="focusable"format="boolean"/>...</declare-styleable><declare-styleablename="TextView"><attrname="text"format="string"localization="suggested"/><attrname="hint"format="string"/><attrname="textColor"/><attrname="textColorHighlight"/><attrname="textColorHint"/>...</declare-styleable><declare-styleablename="ViewGroup_Layout"><attrname="layout_width"format="dimension"><enumname="fill_parent"value="-1"/><enumname="match_parent"value="-1"/><enumname="wrap_content"value="-2"/></attr><attrname="layout_height"format="dimension"><enumname="fill_parent"value="-1"/><enumname="match_parent"value="-1"/><enumname="wrap_content"value="-2"/></attr></declare-styleable><declare-styleablename="LinearLayout_Layout"><attrname="layout_width"/><attrname="layout_height"/><attrname="layout_weight"format="float"/><attrname="layout_gravity"/></declare-styleable><declare-styleablename="RelativeLayout_Layout"><attrname="layout_centerInParent"format="boolean"/><attrname="layout_centerHorizontal"format="boolean"/><attrname="layout_centerVertical"format="boolean"/>...</declare-styleable>看看上面attrs.xml文件中的属性,发现他们都是有规律的分组的形式组织的。以declare-styleable为一个组合,后面有一个name属性,属性的值为View、TextView等等,有没有想到什么?没错,属性值为View的那一组就是为View定义的属性,属性值为TextView的就是为TextView定义的属性…。  因为所有的控件都是View的子类,所以为View定义的属性所有的控件都能使用,这就是为什么我们的自定义控件没有定义属性就能使用一些系统属性。  但是并不是每个控件都能使用所有属性,比如TextView是View的子类,所以为View定义的所有属性它都能使用,但是子类肯定有自己特有的属性,得单独为它扩展一些属性,而单独扩展的这些属性只有它自己能有,View是不能使用的,比如View中不能使用android:text=“”。又比如,LinearLayout中能使用layout_weight属性,而RelativeLayout却不能使用,因为layout_weight是为LinearLayout的LayoutParams定义的。  综上所述,自定义控件如果不自定义属性,就只能使用VIew的属性,但为了给我们的控件扩展一些属性,我们就必须自己去定义。2.怎样自定义属性  翻阅系统的属性文件,你会发现,有的这中形式,有的是;这两种的区别就是attr标签后面带不带format属性,如果带format的就是在定义属性,如果不带format的就是在使用已有的属性,name的值就是属性的名字,format是限定当前定义的属性能接受什么值。  打个比方,比如系统已经定义了android:text属性,我们的自定义控件也需要一个文本的属性,可以有两种方式:第一种:我们并不知道系统定义了此名称的属性,我们自己定义一个名为text或者mText的属性(属性名称可以随便起的)<resources><declare-styleablename="MyTextView"><attrname=“text"format="string"/></declare-styleable></resources>第二种:我们知道系统已经定义过名称为text的属性,我们不用自己定义,只需要在自定义属性中申明,我要使用这个text属性(注意加上android命名空间,这样才知道使用的是系统的text属性)<resources><declare-styleablename="MyTextView"><attrname=“android:text"/></declare-styleable></resources>  为什么系统定义了此属性,我们在使用的时候还要声明?因为,系统定义的text属性是给TextView使用的,如果我们不申明,就不能使用text属性。3.属性值的类型formatformat支持的类型一共有11种:(1).reference:参考某一资源ID属性定义:<declare-styleablename="名称"><attrname="background"format="reference"/></declare-styleable>属性使用:<ImageViewandroid:background="@drawable/图片ID"/>(2).color:颜色值属性定义:<attrname="textColor"format="color"/>属性使用:<TextViewandroid:textColor="#00FF00"/>(3).boolean:布尔值属性定义:<attrname="focusable"format="boolean"/>属性使用:<Buttonandroid:focusable="true"/>(4).dimension:尺寸值属性定义:<attrname="layout_width"format="dimension"/>属性使用:<Buttonandroid:layout_width="42dip"/>(5).float:浮点值属性定义:<attrname="fromAlpha"format="float"/>属性使用:<alphaandroid:fromAlpha="1.0"/>(6).integer:整型值属性定义:<attrname="framesCount"format="integer"/>属性使用:<animated-rotateandroid:framesCount="12"/>(7).string:字符串属性定义:<attrname="text"format="string"/>属性使用:<TextViewandroid:text="我是文本"/>(8).fraction:百分数属性定义:<attrname="pivotX"format="fraction"/>属性使用:<rotateandroid:pivotX="200%"/>(9).enum:枚举值属性定义:<declare-styleablename="名称"><attrname="orientation"><enumname="horizontal"value="0"/><enumname="vertical"value="1"/></attr></declare-styleable>属性使用:<LinearLayoutandroid:orientation="vertical"></LinearLayout>注意:枚举类型的属性在使用的过程中只能同时使用其中一个,不能android:orientation=“horizontal|vertical"(10).flag:位或运算属性定义:<declare-styleablename="名称"><attrname="gravity"><flagname="top"value="0x30"/><flagname="bottom"value="0x50"/><flagname="left"value="0x03"/><flagname="right"value="0x05"/><flagname="center_vertical"value="0x10"/>...</attr></declare-styleable>属性使用:<TextViewandroid:gravity="bottom|left"/>注意:位运算类型的属性在使用的过程中可以使用多个值(11).混合类型:属性定义时可以指定多种类型值属性定义:<declare-styleablename="名称"><attrname="background"format="reference|color"/></declare-styleable>属性使用:<ImageViewandroid:background="@drawable/图片ID"/>或者:<ImageViewandroid:background="#00FF00"/>  通过上面的学习我们已经知道怎么定义各种类型的属性,以及怎么使用它们,但是我们写好布局文件之后,要在控件中使用这些属性还需要将它解析出来。4.类中获取属性值  在这之前,顺带讲一下命名空间,我们在布局文件中使用属性的时候(android:layout_width="match_parent")发现前面都带有一个android:,这个android就是上面引入的命名空间xmlns:android="/apk/res/android”,表示到android系统中查找该属性来源。只有引入了命名空间,XML文件才知道下面使用的属性应该去哪里找(哪里定义的,不能凭空出现,要有根据)。  如果我们自定义属性,这个属性应该去我们的应用程序包中找,所以要引入我们应用包的命名空间xmlns:openxu="/apk/res-auto”,res-auto表示自动查找,还有一种写法xmlns:openxu="/apk/com.example.openxu.myview",com.example.openxu.myview为我们的应用程序包名。  按照上面学习的知识,我们先定义一些属性,并写好布局文件。先在res\values目录下创建attrs.xml,定义自己的属性:<?xmlversion="1.0"encoding="utf-8"?><resources><declare-styleablename="MyTextView"><!--声明MyTextView需要使用系统定义过的text属性,注意前面需要加上android命名--><attrname="android:text"/><attrname="mTextColor"format="color"/><attrname="mTextSize"format="dimension"/></declare-styleable></resources>在布局文件中,使用属性(注意引入我们应用程序的命名空间,这样在能找到我们包中的attrs):<LinearLayoutxmlns:android="/apk/res/android"xmlns:tools="/tools"xmlns:openxu="/apk/res-auto"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><com.example.openxu.myview.MyTextViewandroid:layout_width="200dip"android:layout_height="100dip"openxu:mTextSize="25sp"android:text="我是文字"openxu:mTextColor="#0000ff"android:background="#ff0000"/></LinearLayout>在构造方法中获取属性值:publicMyTextView(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);TypedArrayta=context.obtainStyledAttributes(attrs,R.styleable.MyTextView);Stringtext=ta.getString(R.styleable.MyTextView_android_text);intmTextColor=ta.getColor(R.styleable.MyTextView_mTextColor,Color.BLACK);intmTextSize=ta.getDimensionPixelSize(R.styleable.MyTextView_mTextSize,100);ta.recycle();//注意回收Log.v("openxu",“text属性值:"+mText);Log.v("openxu","mTextColor属性值:"+mTextColor);Log.v("openxu","mTextSize属性值:"+mTextSize);}log输出:05-2100:14:07.192:V/openxu(25652):mText属性值:我是文字05-2100:14:07.192:V/openxu(25652):mTextColor属性值:-1677696105-2100:14:07.192:V/openxu(25652):mTextSize属性值:75到此为止,是不是发现自定义属性是如此简单?属性的定义我们应该学的差不多了,但有没有发现构造方法中获取属性值的时候有两个比较陌生的类AttributeSet和TypedArray,这两个类是怎么把属性值从布局文件中解析出来的?5.Attributeset和TypedArray以及declare-styleable  Attributeset看名字就知道是一个属性的集合,实际上,它内部就是一个XML解析器,帮我们将布局文件中该控件的所有属性解析出来,并以key-value的兼职对形式维护起来。其实我们完全可以只用他通过下面的代码来获取我们的属性就行。publicMyTextView(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);intcount=attrs.getAttributeCount();for(inti=0;i<count;i++){StringattrName=attrs.getAttributeName(i);StringattrVal=attrs.getAttributeValue(i);Log.e("openxu","attrName="+attrName+",attrVal="+attrVal);}}log输出:05-2102:18:09.052:E/openxu(14704):attrName=background,attrVal=@213142734705-2102:18:09.052:E/openxu(14704):attrName=layout_width,attrVal=200.0dip05-2102:18:09.052:E/openxu(14704):attrName=layout_height,attrVal=100.0dip05-2102:18:09.052:E/openxu(14704):attrName=text,attrVal=我是文字05-2102:18:09.052:E/openxu(14704):attrName=mTextSize,attrVal=25sp05-2102:18:09.052:E/openxu(14704):attrName=mTextColor,attrVal=#0000ff  发现通过Attributeset获取属性的值时,它将我们布局文件中的值原原本本的获取出来的,比如宽度200.0dip,其实这并不是我们想要的,如果我们接下来要使用宽度值,我们还需要将dip去掉,然后转换成整形,这多麻烦。其实这都不算什么,更恶心的是,backgroud我应用了一个color资源ID,它直接给我拿到了这个ID值,前面还加了个@,接下来我要自己获取资源,并通过这个ID值获取到真正的颜色。我们再换TypedArray试试。  在这里,穿插一个知识点,定义属性的时候有一个declare-styleable,他是用来干嘛的,如果不要它可不可以?答案是可以的,我们自定义属性完全可以写成下面的形式:<?xmlversion="1.0"encoding="utf-8"?><resources><attrname="mTextColor"format="color"/><attrname="mTextSize"format="dimension"/></resources>之前的形式是这样的:<?xmlversion="1.0"encoding="utf-8"?><resources><declare-styleablename="MyTextView"><attrname="android:text"/><attrname="android:layout_width"/><attrname="android:layout_height"/><attrname="android:background"/><attrname="mTextColor"format="color"/><attrname="mTextSize"format="dimension"/></declare-styleable></resources>或者:<?xmlversion="1.0"encoding="utf-8"?><resources><!--定义属性--><attrname="mTextColor"format="color"/><attrname="mTextSize"format="dimension"/><declare-styleablename="MyTextView"><!--生成索引--><attrname="android:text"/><attrname="android:layout_width"/><attrname="android:layout_height"/><attrname="android:background"/><attrname=“mTextColor"/><attrname="mTextSize"/></declare-styleable></resources>  我们都知道所有的资源文件在R中都会对应一个整型常亮,我们可以通过这个ID值找到资源文件。  属性在R中对应的类是publicstaticfinalclassattr,如果我们写了declare-styleable,在R文件中就会生成styleable类,这个类其实就是将每个控件的属性分组,然后记录属性的索引值,而TypedArray正好需要通过此索引值获取属性。publicstaticfinalclassstyleablepublicstaticfinalint[]MyTextView={0x0101014f,0x7f010038,0x7f010039};publicstaticfinalintMyTextView_android_text=0;publicstaticfinalintMyTextView_mTextColor=1;publicstaticfinalintMyTextView_mTextSize=2;}使用TypedArray获取属性值:publicMyTextView(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);TypedArrayta=context.obtainStyledAttributes(attrs,R.styleable.MyTextView);StringmText=ta.getString(R.styleable.MyTextView_android_text);intmTextColor=ta.getColor(R.styleable.MyTextView_mTextColor,Color.BLACK);intmTextSize=ta.getDimensionPixelSize(R.styleable.MyTextView_mTextSize,100);floatwidth=ta.ge

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论