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)
blank

相关推荐

  • C语言实现学生成绩管理系统(EasyX图形界面)

    C语言实现学生成绩管理系统(EasyX图形界面)我的小站——半生瓜のblog代码文件下载链接——链接学生成绩管理系统学生成绩管理系统效果图流程&注意要点代码实现学生成绩管理系统效果图流程&注意要点核心部分——EasyX显示图形界面,结构体数组和文件操作负责对数据进行各种操作。只要一进去程序就对存储数据的文件进行读取,如果有数据直接读到学生结构体数组里面,得到当前结构体数组中的数据数量(几个人),并将所有数据打印到屏幕上。管理员用户输入密码验证——读取文件——验证用户输入是否正确。显示所有数据——如果通过文件.

  • 多因子权重算法_SEO权重优化软件

    多因子权重算法_SEO权重优化软件from:https://www.ricequant.com/community/topic/4559/在多因子量化投资体系中,具有稳定的预期收益,可解释的经济驱动理论,与其他因子的低相关性是选择alpha因子的关键指标。本篇文章中,我们以此为因子选取标准,简单地构建了自己的因子库,总共包括八个大类因子,每个大类因子中包含四到五个子类细分因子。为了比较不同的权重优化方法的优劣,本文首先采取不同的方…

  • java必背代码_Java编程中必须要死记硬背的几十个代码段

    java必背代码_Java编程中必须要死记硬背的几十个代码段向文件末尾添加内容字符串有整型的相互转换转字符串到日期java.util.Date=java.text.DateFormat.getDateInstance().parse(dateString);得到当前方法的名字StringmethodName=Thread.currentThread().getStackTrace()[1].getMethodName();使用JDBC链接O…

  • Linux环境下第一次提交项目

    Linux环境下第一次提交项目

    2021年10月17日
  • MMC卡的文件系统及其实现方法

    MMC卡的文件系统及其实现方法引言多媒体卡MMC(MultiMediaCard)是由美国SanDisk公司和德国Simens公司于1997年共同开发推出的一种多功能存储卡。内置控制电路,可以使用在手机、数码相机、MP3、PDA等多种数字设备上,可反复记录30万次。现在市场上的主流容量有128MB~2GB。文中首先介绍单片机对SPI协议下的MMC卡的底层读写操作,然后分析MMC卡文件系统的结构,最…

  • pycharm导出依赖包_pycharm快速倒包

    pycharm导出依赖包_pycharm快速倒包一般你在pycharm本身库里面导入一个外部没有的包这个时候pycharm里面就会报错,所以你要先下载好你想要导入的包,步骤如下:

发表回复

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

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