android attrs获取_Android中如何利用attrs和styles定义控件

android attrs获取_Android中如何利用attrs和styles定义控件一直有个问题就是,Android中是如何通过布局文件,就能实现控件效果的不同呢?比如在布局文件中,我设置了一个TextView,给它设置了textColor,它就能够改变这个TextView的文本的颜色。这是如何做到的呢?我们分3个部分来看这个问题1.attrs.xml2.styles.xml3.看组件的源码。1.attrs.xml:我们知道Android的源码中有attrs.xml这个…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

一直有个问题就是,Android中是如何通过布局文件,就能实现控件效果的不同呢?比如在布局文件中,我设置了一个TextView,给它设置了 textColor,它就能够改变这个TextView的文本的颜色。这是如何做到的呢?我们分3个部分来看这个问题1.attrs.xml  2.styles.xml  3.看组件的源码。

1.attrs.xml:

我们知道Android的源码中有attrs.xml这个文件,这个文件实际上定义了所有的控件的属性,就是我们在布局文件中设置的各类属性

你可以找到attrs.xml这个文件,打开它,全选,右键->Show In->OutLine。可以看到整个文件的解构

下面是两个截图:

android attrs获取_Android中如何利用attrs和styles定义控件

android attrs获取_Android中如何利用attrs和styles定义控件

我们大概可以看出里面是Android中的各种属性的声明,比如textStyle这个属性是这样定义的:

那么现在你知道,我们在写android:textStyle的时候为什么会出现normal,bold和italic这3个东西了吧,就是定义在这个地方。

再看看textColor:

format的意思是说:这个textColor可以以两种方式设置,要么是关联一个值,要么是直接设置一个颜色的RGB值,这个不难理解,因为我们可以平时也这样做过。

也就是说我们平时在布局文件中所使用的各类控件的属性都定义在这里面,那么这个文件,除了定义这些属性外还定义了各种具体的组件,比如TextView,Button,SeekBar等所具有的各种特有的属性

比如SeekBar:

也许你会问SeekBar的background,等属性怎么没有看到?这是因为Android中几乎所有的组件都是从View中继承下来 的,SeekBar自然也不例外,而background这个属性几乎每个控件都有,因此被定义到了View中,你可以在declare- styleable:View中找到它。

总结下,也就是说attrs.xml这个文件定义了布局文件中的各种属性attr:***,以及每种控件特有的属性declare-styleable:***

2.styles.xml:

刚才的attrs.xml定义的是组件的属性,现在要说的style则是针对这些属性所设置的值,一些默认的值。

android attrs获取_Android中如何利用attrs和styles定义控件

这个是SeekBar的样式,我们可以看到,这里面设置了一个SeekBar的默认的样式,即为attrs.xml文件中的各种属性设置初始值

false

@android:drawable/progress_horizontal

@android:drawable/progress_horizontal

20dip

20dip

@android:drawable/seek_thumb

8dip

true

这个是Button的样式:

@android:drawable/btn_default

true

true

?android:attr/textAppearanceSmallInverse

@android:color/primary_text_light

center_vertical|center_horizontal

有了属性和值,但是这些东西是如何关联到一起的呢?它们如何被android的framework层所识别呢?

3.组件的源码

我们看下TextView的源码:

publicTextView(Context context) {this(context, null);

}//这个构造器用来给用户调用,比如new TextView(this);

publicTextView(Context context,

AttributeSet attrs) {this(context, attrs, com.android.internal.R.attr.textViewStyle);

}publicTextView(Context context,

AttributeSet attrs,intdefStyle) {

super(context, attrs, defStyle);//为用户自定义的TextView设置默认的style

mText = “”;//设置画笔

mTextPaint = newTextPaint(Paint.ANTI_ALIAS_FLAG);

mTextPaint.density=getResources().getDisplayMetrics().density;

mTextPaint.setCompatibilityScaling(

getResources().getCompatibilityInfo().applicationScale);

mHighlightPaint= newPaint(Paint.ANTI_ALIAS_FLAG);

mHighlightPaint.setCompatibilityScaling(

getResources().getCompatibilityInfo().applicationScale);

mMovement=getDefaultMovementMethod();

mTransformation= null;//attrs中包含了这个TextView控件在布局文件中定义的属性,比如android:background,android:layout_width等//com.android.internal.R.styleable.TextView中包含了TextView中的针对attrs中的属性的默认的值//也就是说这个地方能够将布局文件中设置的属性获取出来,保存到一个TypeArray中,为这个控件初始化各个属性

TypedArray a =context.obtainStyledAttributes(

attrs, com.android.internal.R.styleable.TextView, defStyle, 0);int textColorHighlight = 0;

ColorStateList textColor= null;

ColorStateList textColorHint= null;

ColorStateList textColorLink= null;int textSize = 15;int typefaceIndex = -1;int styleIndex = -1;/** Look the appearance up without checking first if it exists because

* almost every TextView has one and it greatly simplifies the logic

* to be able to parse the appearance first and then let specific tags

* for this View override it.*/TypedArray appearance= null;//TextView_textAppearance不太了解为什么要这样做?难道是为了设置TextView的一些默认的属性?

int ap = a.getResourceId(com.android.internal.R.styleable.TextView_textAppearance, -1);if (ap != -1) {

appearance=context.obtainStyledAttributes(ap,

com.android.internal.R.styleable.

TextAppearance);

}if (appearance != null) {int n =appearance.getIndexCount();for (int i = 0; i < n; i++) {int attr =appearance.getIndex(i);switch(attr) {case com.android.internal.R.styleable.TextAppearance_textColorHighlight:

textColorHighlight=appearance.getColor(attr, textColorHighlight);break;case com.android.internal.R.styleable.TextAppearance_textColor:

textColor=appearance.getColorStateList(attr);break;case com.android.internal.R.styleable.TextAppearance_textColorHint:

textColorHint=appearance.getColorStateList(attr);break;case com.android.internal.R.styleable.TextAppearance_textColorLink:

textColorLink=appearance.getColorStateList(attr);break;case com.android.internal.R.styleable.TextAppearance_textSize:

textSize=appearance.getDimensionPixelSize(attr, textSize);break;case com.android.internal.R.styleable.TextAppearance_typeface:

typefaceIndex= appearance.getInt(attr, -1);break;case com.android.internal.R.styleable.TextAppearance_textStyle:

styleIndex= appearance.getInt(attr, -1);break;

}

}

appearance.recycle();

}//各类属性

boolean editable =getDefaultEditable();

CharSequence inputMethod= null;int numeric = 0;

CharSequence digits= null;

boolean phone= false;

boolean autotext= false;int autocap = -1;int buffertype = 0;

boolean selectallοnfοcus= false;

Drawable drawableLeft= null, drawableTop = null, drawableRight = null,

drawableBottom= null;int drawablePadding = 0;int ellipsize = -1;

boolean singleLine= false;int maxlength = -1;

CharSequence text= “”;

CharSequence hint= null;int shadowcolor = 0;float dx = 0, dy = 0, r = 0;

boolean password= false;int inputType =EditorInfo.TYPE_NULL;int n =a.getIndexCount();for (int i = 0; i < n; i++) {int attr =a.getIndex(i);//通过switch语句将用户设置的,以及默认的属性读取出来并初始化

switch(attr) {case com.android.internal.R.styleable.TextView_editable:

editable=a.getBoolean(attr, editable);break;case com.android.internal.R.styleable.TextView_inputMethod:

inputMethod=a.getText(attr);break;case com.android.internal.R.styleable.TextView_numeric:

numeric=a.getInt(attr, numeric);break;//更多的case语句…

case com.android.internal.R.styleable.TextView_textSize:

textSize= a.getDimensionPixelSize(attr, textSize);//设置当前用户所设置的字体大小

break;case com.android.internal.R.styleable.TextView_typeface:

typefaceIndex=a.getInt(attr, typefaceIndex);break;//更多的case语句…

}

通过上面的代码大概可以知道,每个组件基本都有3个构造器,其中只传递一个Context上下文的那个构造器一般用来在java代码中实例化使用。

比如你可以

TextView tv = new TextView(context);

来实例化一个组件。

最终调用的是第3个构造器

publicTextView(Context context,

AttributeSet attrs,int defStyle)

在这个构造器中为你设置了默认的属性attrs和值styles。关键不在这里,而是后面通过使用下面的代码

TypedArray a =context.obtainStyledAttributes(

attrs, com.android.internal.R.styleable.TextView, defStyle, 0);

来将属性和值获取出来,放到一个TypeArray中,然后再利用一个switch语句将里面的值取出来。再利用这些值来初始化各个属性。这个View最终利用这些属性将这个控件绘制出来。

如果你在布局文件中定义的一个View的话,那么你定义的值,会被传递给构造器中的attrs和styles。也是利用同样的方式来获取出你定义的值,并根据你定义的值来绘制你想要的控件。

再比如其实Button和EditText都是继承自TextView。看上去两个控件似乎差异很大,其实不然。Button的源码其实相比TextView变化的只是style而已:

public classButton extends TextView {publicButton(Context context) {this(context, null);

}publicButton(Context context, AttributeSet attrs) {this(context, attrs, com.android.internal.R.attr.buttonStyle);

}public Button(Context context, AttributeSet attrs, intdefStyle) {

super(context, attrs, defStyle);

}

}

再看看EditText:

public classEditText extends TextView {publicEditText(Context context) {this(context, null);

}publicEditText(Context context, AttributeSet attrs) {this(context, attrs, com.android.internal.R.attr.editTextStyle);

}public EditText(Context context, AttributeSet attrs, intdefStyle) {

super(context, attrs, defStyle);

}

@Overrideprotectedboolean getDefaultEditable() {return true;

}

@OverrideprotectedMovementMethod getDefaultMovementMethod() {returnArrowKeyMovementMethod.getInstance();

}

@OverridepublicEditable getText() {return(Editable) super.getText();

}

@Overridepublic voidsetText(CharSequence text, BufferType type) {

super.setText(text, BufferType.EDITABLE);

}/**

* Convenience for {@link Selection#setSelection(Spannable, int, int)}.*/

public void setSelection(int start, intstop) {

Selection.setSelection(getText(), start, stop);

}/**

* Convenience for {@link Selection#setSelection(Spannable, int)}.*/

public void setSelection(intindex) {

Selection.setSelection(getText(), index);

}/**

* Convenience for {@link Selection#selectAll}.*/

public voidselectAll() {

Selection.selectAll(getText());

}/**

* Convenience for {@link Selection#extendSelection}.*/

public void extendSelection(intindex) {

Selection.extendSelection(getText(), index);

}

@Overridepublic voidsetEllipsize(TextUtils.TruncateAt ellipsis) {if (ellipsis ==TextUtils.TruncateAt.MARQUEE) {throw new IllegalArgumentException(“EditText cannot use the ellipsize mode”

+ “TextUtils.TruncateAt.MARQUEE”);

}

super.setEllipsize(ellipsis);

}

}

不知道你是不是和我一样感到意外呢?

不得不说这种方式非常的好。最大程度地利用了继承,并且可以让控件之间的属性可以很方便的被开发者使用。也利用以后的扩展,实际上,不同的style就可以得到不同的UI,这也是MVC的一种体现。

比如用户想自定义某个控件,只要覆盖父类的style就可以很轻松的实现,可以参考我的一篇博文,就是使用style自定义ProgressBar。

Android中的主题theme也是使用的style。当用户在Activity中设置一个style的时候那么会影响到整个Activity,如果为Application设置style的话,则会影响所有的Activity,所以,如果你在开发一个应用的时候

可以考虑将应用的Activity的背景颜色等一类的属性放到一个style中去,在Application中调用,这种做法会比较方便。

themes.xml:

true

true

@null

我们平时使用的主题实际上就定义在这个文件中。也是一个style。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/180772.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • MVC三层架构各层含义[通俗易懂]

    MVC三层架构各层含义[通俗易懂]1.模拟架构图:2.Action/Service/DAO简介:Action是管理业务(Service)调度和管理跳转的。Service是管理具体的功能的。Action只负责管理,而Service负责实施。DAO只完成增删改查,虽然可以1-n,n-n,1-1关联,模糊、动态、子查询都可以。但是无论多么复杂的查询,dao只是封装增删改查。至于增删查改如何去实现一个功能,dao是不管…

  • 网络传真的安装及使用方法「建议收藏」

    网络传真的安装及使用方法「建议收藏」在宽带网迅速普及的今天,Modem好像已经“廉颇老矣”,传真Modem已变成了一块“食之无味,弃之可惜”的鸡肋。而且windows的传真模块,已经远远无法满足今天人们快节奏的工作效率。在国外已经非常普遍的网络传真(efax),终于来到了国内,从2004年的引进到根据国内人们使用习惯的不断改进,近10年来,已拥有了百万级的客户群体,特别是近年来,传真营销被企业广泛应用,带来了越来越多的垃圾传

  • bm3d matlab,Note — BM3D「建议收藏」

    bm3d matlab,Note — BM3D「建议收藏」一、引言二、理论三、算法一、引言前面一篇说到Non-localmethod[1],可以归类到spatialmethod中,另外用的比较多的还有transformmethod,基于transformmethod的方法在imagedenoise中也取得了很好的效果,不过理论阐述会比较繁琐,如BLS-GSM-Wavelet。NLM去噪算法使用的是inter-patchcorrelation,而Wavel…

  • tensorRT7+ DEB安装教程

    tensorRT7+ DEB安装教程ONNX转tensorRT1.安装环境建议基于nvidia/cuda镜像,搭建环境!

  • 原码,补码,二进制减法计算_二进制的原码和补码

    原码,补码,二进制减法计算_二进制的原码和补码这篇博客从一道题说起,已知x = (1&lt;&lt;31)-3,求x&amp;-x?这里面考察了二进制的减法,减法也就牵涉了原码补码的一些概念。这里进行下梳理。 一。原码,补码概念1.原码就是早期用来表示数字的一种方式。一个正数,转换为二进制位就是这个正数的原码。负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码例如:假设机器是32位系统,in…

  • 给在读研究生&未来要读研同学们的一封受益匪浅的信

    给在读研究生&未来要读研同学们的一封受益匪浅的信读研首先要改变的是自己的心理状态,说起来简单,但实际上很困难。不过既然已经上了研,就不要抱怨了,努力想想自己该干啥才是王道。首先需要明确几种好的心态。(仅以此文使自己进步,时时规范自己的行为。谦虚使人进步,骄傲使人落后。)当你上课感觉就像打酱油时,当你对研究生很迷茫时,当你坐在电脑前孜孜不倦时,请看下面的文章,很受用,至少我心里现在没有以前浮躁。好的文章有时能改变一个人的精神状态,下面就是…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号