首页编程declare-styleable(Android 中 declare-styleable 和 style 的不同)

declare-styleable(Android 中 declare-styleable 和 style 的不同)

编程之家2023-10-31247次浏览

大家好,今天我将向大家分享有关declare-styleable和Android 中 declare-styleable 和 style 的不同的一些独特见解,希望能够为你们带来新的思考和启示。

declare-styleable(Android 中 declare-styleable 和 style 的不同)

Android自定义属性TypedArray详解

大家好,我是程序员双木L,后续会发专题类的文章,这是自定义控件的第一篇,之后也会陆续更新相关的文章,欢迎关注。

自定义属性在自定义控件过程中属于比较常见的操作,我们可以回想一下这样的场景:自定义view的过程中,我们需要在不同的情况下设置不同的文字大小,那么我们是不是就需要提供对外的方法来设置,这样就比较灵活操作。而我们自定义对外的方法,就是我们自定义的属性啦,那我们来分析一下其原理及作用。

下面我们根据例子来进行分析:

declare-styleable(Android 中 declare-styleable 和 style 的不同)

1、首先我们需要在res->values目录下新建attrs.xml文件,该文件就是用来声明属性名及其接受的数据格式的,如下:

attr名词解析:

name表示属性名,上面的属性名是我自己定义的。

declare-styleable(Android 中 declare-styleable 和 style 的不同)

format表示接受的输入格式,format格式集合如下:

2、自定义属性的使用,这里我们使用两种方式进行对比解析

最最最原始的使用方式

(1)、自定义文件如下:

我们可以在TestAttrsView方法的参数AttributeSet是个xml解析工具类,帮助我们从布局的xml里提取属性名和属性值。

(2)、在布局文件xml中的使用

这里使用自定义属性需要声明xml的命名空间,其中app是命名空间,用来加在自定义属性前面。

xmlns:app=" http://schemas.android.com/apk/res-auto"

声明xml命名空间,xmlns意思为“xml namespace”.冒号后面是给这个引用起的别名。

schemas是xml文档的两种约束文件其中的一种,规定了xml中有哪些元素(标签)、

元素有哪些属性及各元素的关系,当然从面向对象的角度理解schemas文件可以

认为它是被约束的xml文档的“类”或称为“模板”。

(3)、将属性名与属性值打印结果如下:

从打印结果我们可以看出,AttributeSet将布局文件xml下的属性全部打印出来了,细心的童鞋可能已经看出来:

这个属性我们设置的是一个整数尺寸,可最后打印出来的是资源编号。

那如果我们想要输出我们设置的整数尺寸,需要怎么操作呢?

这个时候就该我们这篇的主角出场了,使用TypedArray方式。

(1)、这里我们需要将attrs.xml使用“declare-styleable”标签进行改造,如下:

从改造后的attrs文件可以看出,我们将属性声明归结到TestStyleable里面,也就意味着这些属性是属于TestStyleable下的。

(2)、属性的解析:

这里我直接打印出解析结果,这里可以获取我们想要的自定义属性,而系统有的属性可以忽略。

(3)、运行结果如下

从解析的结果可以看出,尺寸的结果已经转换为实际值了:

这个时候有童鞋又问了,我设置的是15dp,为啥最后打印是41.25了呢?其实解析出来的值单位是px,所以这里输出的是转换后的值。

解析的过程中用到了这个方法:

我们来看一下这个方法的源码:

源码中我们可以看到这个方法有两个参数:

obtainStyledAttributes方法返回值类型为TypedArray。该类型记录了获取到的属性值集合,而通过数组下标索引即可找到对应的属性值。索引下标通过R.styleable.TestStyleable_xx获取,"xx"表示属性名,一般命名为"styleable名"+"_"+"属性名"。

而TypedArray提供了各种Api,如getInteger,getString,getDimension等方法来获取属性值,这些方法都需要传入对应属性名在obtainStyledAttributes中的int数组的位置索引,通过下标获取数组里属性值。

这个TypedArray的作用就是资源的映射作用,把自定义属性在xml设置值映射到class,这样怎么获取都很简单啦。

到这里就分析完啦!

android 自定义switch样式

修改后的MySwitch控件接口基本与原Switch控件一致,并且除了可支持所有SDK外,增加了2项小功能:

1.支持用Track背景图片的方式代替Texton Textoff等文字方式表现开关状态

2.支持调整控制Switch的高度

下面贴出Switch修改的关键代码:

/**

*<p>

* modified from android SDK 14(4.0) android.widget.Switch.

*<br/>

*<strong>new feature:</strong>

*<ol>

*<li>support SDK 1 or higher.</li>

*<li>you can use track drawable instead of text to display the changes of off-on state!</li>

*<li>you can control the Switch minimum height.</li>

*</ol>

*</p>

*

*@see{@link Switch}

*@author Wison

*/

public class MySwitch extends CompoundButton{

// Support track drawable instead of text

private Drawable mTrackOnDrawable;

private Drawable mTrackOffDrawable;

// Support minimum height

private int mSwitchMinHeight;

/**

* Construct a new Switch with a default style determined by the given theme attribute,

* overriding specific style attributes as requested.

*

*@param context The Context that will determine this widget's theming.

*@param attrs Specification of attributes that should deviate from the default styling.

*@param defStyle An attribute ID within the active theme containing a reference to the

* default style for this widget. e.g. android.R.attr.switchStyle.

*/

public MySwitch(Context context, AttributeSet attrs, int defStyle){

super(context, attrs, defStyle);

mTextPaint= new TextPaint(Paint.ANTI_ALIAS_FLAG);

Resources res= getResources();

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

//float scaledDensity= res.getDisplayMetrics().scaledDensity;

//mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);

TypedArray a= context.obtainStyledAttributes(attrs, R.styleable.Switch, defStyle, 0);

// off-on模式:图片模式或文字模式,图片模式是用Track背景图片表示off-on的状态,文字模式是用文字来表示off-on状态。

mTrackOnDrawable= a.getDrawable(R.styleable.Switch_trackOn);

mTrackOffDrawable= a.getDrawable(R.styleable.Switch_trackOff);

if(checkTrackOffOnDrawable()){

//如果设定图片模式,则默认显示off状态

mTrackDrawable= mTrackOffDrawable;

} else{

mTrackDrawable= a.getDrawable(R.styleable.Switch_track);

}

mThumbDrawable= a.getDrawable(R.styleable.Switch_thumb);

mTextOn= a.getText(R.styleable.Switch_textOn);

mTextOff= a.getText(R.styleable.Switch_textOff);

mThumbTextPadding= a.getDimensionPixelSize(R.styleable.Switch_thumbTextPadding, 0);

mSwitchMinWidth= a.getDimensionPixelSize(R.styleable.Switch_switchMinWidth, 0);

mSwitchMinHeight= a.getDimensionPixelSize(R.styleable.Switch_switchMinHeight, 0);

mSwitchPadding= a.getDimensionPixelSize(R.styleable.Switch_switchPadding, 0);

int appearance= a.getResourceId(R.styleable.Switch_switchTextAppearance, 0);

if(appearance!= 0){

setSwitchTextAppearance(context, appearance);

}

a.recycle();

ViewConfiguration config= ViewConfiguration.get(context);

mTouchSlop= config.getScaledTouchSlop();

mMinFlingVelocity= config.getScaledMinimumFlingVelocity();

// Refresh display with current params

refreshDrawableState();

setChecked(isChecked());

}

private boolean checkTrackOffOnDrawable(){

return mTrackOnDrawable!= null&& mTrackOffDrawable!= null;

}

@SuppressLint("NewApi")

@Override

public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){

if(mOnLayout== null){

mOnLayout= makeLayout(mTextOn);

}

if(mOffLayout== null){

mOffLayout= makeLayout(mTextOff);

}

mTrackDrawable.getPadding(mTempRect);

final int maxTextWidth= Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());

final int switchWidth= Math.max(mSwitchMinWidth,

maxTextWidth* 2+ mThumbTextPadding* 4+ mTempRect.left+ mTempRect.right);

// final int switchHeight= mTrackDrawable.getIntrinsicHeight();

int switchHeight;

if(mSwitchMinHeight<= 0){

switchHeight= mTrackDrawable.getIntrinsicHeight();

} else{

switchHeight= Math.max(mSwitchMinHeight, mTempRect.top+ mTempRect.bottom);

}

mThumbWidth= maxTextWidth+ mThumbTextPadding* 2;

mSwitchWidth= switchWidth;

mSwitchHeight= switchHeight;

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

final int measuredHeight= getMeasuredHeight();

if(measuredHeight< switchHeight){

if(Build.VERSION.SDK_INT>= 11){

setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);

} else{

setMeasuredDimension(getMeasuredWidth(), switchHeight);

}

}

}

@Override

public void setChecked(boolean checked){

if(checkTrackOffOnDrawable()){

mTrackDrawable= checked? mTrackOnDrawable: mTrackOffDrawable;

refreshDrawableState();

}

super.setChecked(checked);

mThumbPosition= checked? getThumbScrollRange(): 0;

invalidate();

}

@Override

protected void onDraw(Canvas canvas){

super.onDraw(canvas);

// Draw the switch

int switchLeft= mSwitchLeft;

int switchTop= mSwitchTop;

int switchRight= mSwitchRight;

int switchBottom= mSwitchBottom;

if(checkTrackOffOnDrawable()){

mTrackDrawable= getTargetCheckedState()? mTrackOnDrawable: mTrackOffDrawable;

refreshDrawableState();

}

mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);

mTrackDrawable.draw(canvas);

canvas.save()

mTrackDrawable.getPadding(mTempRect);

int switchInnerLeft= switchLeft+ mTempRect.left;

int switchInnerTop= switchTop+ mTempRect.top;

int switchInnerRight= switchRight- mTempRect.right;

int switchInnerBottom= switchBottom- mTempRect.bottom;

canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);

mThumbDrawable.getPadding(mTempRect);

final int thumbPos=(int)(mThumbPosition+ 0.5f);

int thumbLeft= switchInnerLeft- mTempRect.left+ thumbPos;

int thumbRight= switchInnerLeft+ thumbPos+ mThumbWidth+ mTempRect.right;

mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);

mThumbDrawable.draw(canvas);

// mTextColors should not be null, but just in case

if(mTextColors!= null){

mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(),

mTextColors.getDefaultColor()));

}

mTextPaint.drawableState= getDrawableState();

Layout switchText= getTargetCheckedState()? mOnLayout: mOffLayout;

if(switchText!= null){

canvas.translate((thumbLeft+ thumbRight)/ 2- switchText.getWidth()/ 2,

(switchInnerTop+ switchInnerBottom)/ 2- switchText.getHeight()/ 2);

switchText.draw(canvas);

}

canvas.restore();

}

}

下面是关键属性声明:

<declare-styleable name="Switch">

<!-- Drawable to use when the switch is in the checked/"on" state.-->

<attr name="trackOn" format="reference"/>

<!-- Drawable to use when the switch is in the unchecked/"off" state.-->

<attr name="trackOff" format="reference"/>

<!-- Minimum height for the switch component-->

<attr name="switchMinHeight" format="dimension"/>

<!-- Drawable to use as the"thumb" that switches back and forth.-->

<attr name="thumb" format="reference"/>

<!-- Drawable to use as the"track" that the switch thumb slides within.-->

<attr name="track" format="reference"/>

<!-- Text to use when the switch is in the checked/"on" state.-->

<attr name="textOn" format="string"/>

<!-- Text to use when the switch is in the unchecked/"off" state.-->

<attr name="textOff" format="string"/>

<!-- Amount of padding on either side of text within the switch thumb.-->

<attr name="thumbTextPadding" format="dimension"/>

<!-- TextAppearance style for text displayed on the switch thumb.-->

<attr name="switchTextAppearance" format="reference"/>

<!-- Minimum width for the switch component-->

<attr name="switchMinWidth" format="dimension"/>

<!-- Minimum space between the switch and caption text-->

<attr name="switchPadding" format="dimension"/>

</declare-styleable>

Android 中 declare-styleable 和 style 的不同

我们注意到上文中的CodeFont的定义,有没有发现item里面的name都是android开头?因为这些属性都是在android中预先设定好的,所以我们可以随意用。但是如果我们想用自己定义的属性名呢?这时候styleable的作用就出现了。我们只需要把attr的定义包围在styleable里面,这样定义的属性名就可以在style里面用。示例如下(示例来自上文给出的stackoverflow链接):

<?xml version="1.0" encoding="utf-8"?>

<resources>

<attr name="attrib1" format="string"/>

<declare-styleable name="blahblah">

<attr name="attrib2" format="string"/>

</declare-styleable>

在attrs.xml里面定义了两个attr,attrib1是普通的,attrib2包围在declare-styleable标签中;

<com.custom.ViewClass attrib1="xyz" attrib2="abc"/>

我们可以在layout/someactivity.xml里直接使用这些attr;

<style name="customstyle" parent="@android:style/Widget.TextView">

<item name="attrib2">text value</item>

<!-- customize other, standard attributes too:-->

<item name="android:textColor">@color/white</item>

</style>

在styles.xml中,我们就能用attrib2。(原网站这里写成了attrib1,怀疑是笔误。)

后来我验证过attrib1也能使用在style里面(我真的不确定,逻辑上应该不能才对,但是编译就是通过了。。。),那么这里就必须说明attr包不包含在styleable里面的另一个主要区别了,stackoverflow中是这么说的:

感谢您的阅读!希望本文对解决您关于declare-styleable的问题有所帮助。如果您还有其他疑问,欢迎随时向我们提问。

团购网源码?社区团购小程序多少钱sql学习,怎样学习sql