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。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • CS和BS_cs和bs架构的优缺点

    CS和BS_cs和bs架构的优缺点一、什么是CS和BS结构? 1.C/S又称Client/Server或客户/服务器模式。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如Oracle、Sybase、Informix或SQLServer。客户端需要安装专用的客户端软件。 2.B/S是Brower/Server的缩写,客户机上只要安装一个浏览器(Browser),如NetscapeNavigator或Intern…

    2022年9月10日
    2
  • 简易旋转倒立摆_180度旋转气缸调节角度

    简易旋转倒立摆_180度旋转气缸调节角度旋转倒立摆调节经验前言程序框架关于直立关于自动起摆前言近期在做2013年电赛控制类题目–简易旋转倒立摆装置,自己并不是自动化专业的学生,没有学过自动控制原理,倒立摆其实是一个十分经典的自动控制模型,我们只能是边做边学习,逐渐去了解倒立摆。我认为倒立摆有两个难点,一个是自动起摆一个是机械结构,其中自动起摆涉及到PID算法与运动方程的求解,而机械结构主要是尽量减小转动阻尼同时避免旋转时线的缠绕。…

    2022年8月18日
    6
  • 使用ipv6内网穿透,实现私有云盘搭建,实现远程控制等功能

    使用ipv6内网穿透,实现私有云盘搭建,实现远程控制等功能

    2021年5月18日
    359
  • Hash一致算法_一致性hash是如何做数据迁移

    Hash一致算法_一致性hash是如何做数据迁移概述这里存在一种场景,当一个服务由多个服务器组共同提供时,key应该路由到哪一个服务.这里假如采用最通用的方式key%N(N为服务器数目),这里乍一看没什么问题,但是当服务器数目发送增加或减少时,分配方式则变为key%(N+1)或key%(N-1).这里将会有大量的key失效迁移,如果后端key对应的是有状态的存储数据,那么毫无疑问,这种做法将导致服务器间大量的数据迁移,从而照成

    2022年9月1日
    5
  • TCP协议和UDP协议

    TCP协议和UDP协议1.传输控制协议TCP1.1TCP的主要特点:1.1.1面向连接的运输层协议socket部分讲述tcp连接的建立tcp连接的释放tcp的有限状态机1.1.2每一条TCP连接只能有两个端点,每一条TCP链接只能是点对点的(一对一)1.1.3TCP提供可靠交付的服务可靠传输的工作原理可靠传输的实现流量控制拥塞控制1.1.4TCP提供全双工通信1.1.5面向字节流流式服务的特点1.2与TCP有关的面试问题2.用户数据报协议UDP2.1UDP协

    2022年6月7日
    41
  • pcanywhere设置主控端_redis修改端口

    pcanywhere设置主控端_redis修改端口  有些防火墙只允许一个pcAnywhere被控端使用一个IP端口。而防火墙后面的其它pcAnywhere被控端必须使用另外的端口。希望知道如何更改这些端口。   更改pcAnywhereIP端口需要编辑Windows注册表。如果需要频繁的执行此操作,创建.reg文件是最安全也是最方便的更改方法。尤其对于那些可能需要连接_blank”>防火墙后多个被控端的主控端而

    2022年9月12日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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