View编程(9): TypeArray、attrs.xml

博客 http://blog.youkuaiyun.com/androidbluetooth/article/details/6725005 简单介绍了一下如何自定义 view 以及如何为自定义的 view 定义属性。


这篇博客接着聊聊关于自定义属性。


我们可以在 res/values/attrs.xml 里面自定义属性,那麽可以定义哪些属性,究竟又该如何定义?


在 google 提供的 android doc 上面,除了 apidemo 里面有(下面给出其文档位置信息),在其他地方没有找到具体的说明(如果您找到了告诉我,谢谢),不过在其他地方找到了答案。


sdk根目录:


1)/docs/resources/samples/ApiDemos/res/values/attrs.html

2)/docs/resources/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html


可以定义的种类(10 种):

"reference" //引用

"color" //颜色

"boolean" //布尔值

"dimension" //尺寸值

"float" //浮点值

"integer" //整型值

"string" //字符串

"fraction" //百分数

"Enum" // 枚举

"Flag" // 标志位,可以位运算


具体使用方法(来自 http://googlers.iteye.com/blog/1122585):


1. reference:参考某一资源ID


    (1)属性定义:
            <declare-styleable name = "名称">
                   <attr name = "background" format = "reference" />
            </declare-styleable>


    (2)属性使用:
            <ImageView
                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:background = "@drawable/图片ID"
                     />

2. color:颜色值


    (1)属性定义:
            <declare-styleable name = "名称">
                   <attr name = "textColor" format = "color" />
            </declare-styleable>


    (2)属性使用:
            <TextView
                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:textColor = "#00FF00"
                     />

 3. boolean:布尔值


    (1)属性定义:
            <declare-styleable name = "名称">
                <attr name = "focusable" format = "boolean" />
            </declare-styleable>


    (2)属性使用:
            <Button
                   android:layout_width = "42dip"
                   android:layout_height = "42dip"
                   android:focusable = "true"
                    />
 
4. dimension:尺寸值


     (1)属性定义:
             <declare-styleable name = "名称">
                   <attr name = "layout_width" format = "dimension" />
            </declare-styleable>


    (2)属性使用:
            <Button
                   android:layout_width = "42dip"
                   android:layout_height = "42dip"
                  />

 5. float:浮点值


    (1)属性定义:
            <declare-styleable name = "AlphaAnimation">
                   <attr name = "fromAlpha" format = "float" />
                   <attr name = "toAlpha" format = "float" />
            </declare-styleable>


    (2)属性使用:
            <alpha
                   android:fromAlpha = "1.0"
                   android:toAlpha = "0.7"
                   />
 
6. integer:整型值


    (1)属性定义:


            <declare-styleable name = "AnimatedRotateDrawable">
                   <attr name = "visible" />
                   <attr name = "frameDuration" format="integer" />
                   <attr name = "framesCount" format="integer" />
                   <attr name = "pivotX" />
                   <attr name = "pivotY" />
                   <attr name = "drawable" />
            </declare-styleable>


    (2)属性使用:
            <animated-rotate
                   xmlns:android = "http://schemas.android.com/apk/res/android"  
                   android:drawable = "@drawable/图片ID"  
                   android:pivotX = "50%"  
                   android:pivotY = "50%"  
                   android:framesCount = "12"  
                   android:frameDuration = "100"
                   />
 
7. string:字符串


    (1)属性定义:
            <declare-styleable name = "MapView">
                   <attr name = "apiKey" format = "string" />
            </declare-styleable>


    (2)属性使用:
            <com.google.android.maps.MapView
                    android:layout_width = "fill_parent"
                    android:layout_height = "fill_parent"
                    android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"
                    />


8. fraction:百分数


     (1)属性定义:
            <declare-styleable name="RotateDrawable">
                   <attr name = "visible" />
                   <attr name = "fromDegrees" format = "float" />
                   <attr name = "toDegrees" format = "float" />
                   <attr name = "pivotX" format = "fraction" />
                   <attr name = "pivotY" format = "fraction" />
                   <attr name = "drawable" />
            </declare-styleable>


    (2)属性使用:
            <rotate
                 xmlns:android = "http://schemas.android.com/apk/res/android" 
            android:interpolator = "@anim/动画ID"
                 android:fromDegrees = "0" 
            android:toDegrees = "360"
                 android:pivotX = "200%"
                 android:pivotY = "300%" 
            android:duration = "5000"
                 android:repeatMode = "restart"
                 android:repeatCount = "infinite"
                />


9. enum:枚举值
    (1)属性定义:
            <declare-styleable name="名称">
                   <attr name="orientation">
                          <enum name="horizontal" value="0" />
                          <enum name="vertical" value="1" />
                   </attr>            
            </declare-styleable>


    (2)属性使用:
            <LinearLayout
                    xmlns:android = "http://schemas.android.com/apk/res/android"
                    android:orientation = "vertical"
                    android:layout_width = "fill_parent"
                    android:layout_height = "fill_parent"
                    >
            </LinearLayout>


10. flag:位或运算


     (1)属性定义:
             <declare-styleable name="名称">
                    <attr name="windowSoftInputMode">
                            <flag name = "stateUnspecified" value = "0" />
                            <flag name = "stateUnchanged" value = "1" />
                            <flag name = "stateHidden" value = "2" />
                            <flag name = "stateAlwaysHidden" value = "3" />
                            <flag name = "stateVisible" value = "4" />
                            <flag name = "stateAlwaysVisible" value = "5" />
                            <flag name = "adjustUnspecified" value = "0x00" />
                            <flag name = "adjustResize" value = "0x10" />
                            <flag name = "adjustPan" value = "0x20" />
                            <flag name = "adjustNothing" value = "0x30" />
                     </attr>         
             </declare-styleable>


     (2)属性使用:
            <activity
                   android:name = ".StyleAndThemeActivity"
                   android:label = "@string/app_name"
                   android:windowSoftInputMode = "stateUnspecified|stateUnchanged|stateHidden">
                   <intent-filter>
                          <action android:name = "android.intent.action.MAIN" />
                          <category android:name = "android.intent.category.LAUNCHER" />
                   </intent-filter>
             </activity>


注意:属性定义时可以指定多种类型值。


    (1)属性定义:
            <declare-styleable name = "名称">
                   <attr name = "background" format = "reference|color" />
            </declare-styleable>


    (2)属性使用:
             <ImageView
                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:background = "@drawable/图片ID|#00FF00"
                     />


以上是最基本的知识,要学以致用。注意问题:


1)自定义属性之后,一般要在自定义的 view 里面写一个对应的方法:


例如 text 属性,对应方法 setText。


2)还有就是自定义属性之后,我们可以在自定义 view 类的构造方法里面为其设置默认属性。


比如,用户没有设置 textsize 属性,那麽我们可以默认给它一个值,这样代码更加具有健壮性!


实例代码:


attrs.xml 片段

<declare-styleable name="LabelView">
        <attr name="text" format="string" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
    </declare-styleable>

LableView.java 片段

TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.LabelView);

        CharSequence s = a.getString(R.styleable.LabelView_text);
        if (s != null) {
            setText(s.toString());
        }

        // Retrieve the color(s) to be used for this view and apply them.
        // Note, if you only care about supporting a single color, that you
        // can instead call a.getColor() and pass that to setTextColor().
        setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));

        int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
        if (textSize > 0) {
            setTextSize(textSize);
        }

        a.recycle();


首先,获取 TypeArray 对象,接着,可以使用其提供的方法获取属性对应的值并提供一个默认值。


R.styleable.LabelView_text

表示引用 attrs.xml 中 name 是 LabelView 的 text 属性,二者使用 "_ " 连接!


R.styleable.LabelView_textSize 亦如此!


最后,别忘记 a.recycle() !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 在 api 文档里面有提示(在 TypeArray 类):


Class Overview

Container for an array of values that were retrieved with 
obtainStyledAttributes(AttributeSet, int[], int, int) 
or 
obtainAttributes(AttributeSet, int[]). 


Be sure to call recycle() when done with them. 
The indices used to retrieve values from this structure correspond 
to the positions of the attributes given to obtainStyledAttributes.


更多知识,可以参考学习 android 相关 view 的源码!


推荐一篇不错的博客:http://blog.youkuaiyun.com/Android_Tutor/article/details/5508615


回过头再去看看:


1)/docs/resources/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html


2)android Launcher 源码中关于 attrs.xml 定义以及使用方法。






open class TPTwoLineItemView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.twoLineItemStyle, defStyleRes: Int = R.style.Widget_TPDesign_List_Two ) : TPListItemView( context, attrs, defStyleAttr, defStyleRes ) { final override val itemViewHelper: TPListItemViewHelper by lazy { TPListItemViewHelper(this, R.layout.tpds_list_two_line_item_view) } val content: TextView val label: TextView val tag: TextView init { itemViewHelper.loadFromAttributes(attrs, defStyleAttr, defStyleRes) content = findViewById(R.id.content) label = findViewById(R.id.label) tag = findViewById(R.id.tag) val typeArray = getContext().obtainStyledAttributes( attrs, R.styleable.TPTwoLineItemView, defStyleAttr, defStyleRes ) val contentText = typeArray.getString(R.styleable.TPTwoLineItemView_itemContent) val contentTextColor = typeArray.getColorStateList(R.styleable.TPTwoLineItemView_itemContentTextColor) val contentTextColorHighContrast = typeArray.getColorStateList(R.styleable.TPTwoLineItemView_itemContentTextColorHighContrast) val contentTextAppearance = typeArray.getResourceId(R.styleable.TPTwoLineItemView_itemContentTextAppearance, 0) val labelText = typeArray.getString(R.styleable.TPTwoLineItemView_itemLabel) val labelTextColor = typeArray.getColorStateList(R.styleable.TPTwoLineItemView_itemLabelTextColor) val labelTextColorHighContrast = typeArray.getColorStateList(R.styleable.TPTwoLineItemView_itemLabelTextColorHighContrast) val labelTextAppearance = typeArray.getResourceId(R.styleable.TPTwoLineItemView_itemLabelTextAppearance, 0) val labelBackgroundId = typeArray.getResourceId(R.styleable.TPTwoLineItemView_itemLabelBackground, -1) val labelBackgroundHighContrastId = typeArray.getResourceId(R.styleable.TPTwoLineItemView_itemLabelBackgroundHighContrast, -1) val tagText = typeArray.getString(R.styleable.TPTwoLineItemView_itemTag) val tagTextColor = typeArray.getColorStateList(R.styleable.TPTwoLineItemView_itemTagTextColor) val tagTextColorHighContrast = typeArray.getColorStateList(R.styleable.TPTwoLineItemView_itemTagTextColorHighContrast) val tagTextAppearance = typeArray.getResourceId(R.styleable.TPTwoLineItemView_itemTagTextAppearance, 0) typeArray.recycle() if (contentTextAppearance > 0) { TextViewCompat.setTextAppearance(content, contentTextAppearance) } setContentText(contentText) if (labelTextAppearance > 0) { TextViewCompat.setTextAppearance(label, labelTextAppearance) } setLabelText(labelText) if (tagTextAppearance > 0) { TextViewCompat.setTextAppearance(tag, tagTextAppearance) } setTagText(tagText) //设置tag标准字体色、高对比度字体色 setTPTextViewColors(tag as TPTextView, tagTextColor, tagTextColorHighContrast) //设置content标准字体色、高对比度字体色 setTPTextViewColors(content as TPTextView, contentTextColor, contentTextColorHighContrast) //设置label标准字体色、高对比度字体色 setTPTextViewColors(label as TPTextView, labelTextColor, labelTextColorHighContrast) //设置label标准背景色、高对比度背景色 setLabelBackgrounds(labelBackgroundId, labelBackgroundHighContrastId) } private fun setTPTextViewColors( textView: TPTextView, normalModeColor: ColorStateList?, highContrastModeColor: ColorStateList? ) { normalModeColor?.let { textView.setTextColor(it) } highContrastModeColor?.let { textView.setTextColorResourceHighContrast(it) } } fun setLabelBackgrounds(normalModeBackground: Int?, highContrastModeBackground: Int?) { normalModeBackground?.let { (label as TPTextView).setBackgroundResource(it) } highContrastModeBackground?.let { (label as TPTextView).setBackgroundResourceHighContrast(it) } } fun setLabelTextColors( normalModeColor: ColorStateList?, highContrastModeColor: ColorStateList? ) { setTPTextViewColors(label as TPTextView, normalModeColor, highContrastModeColor) } fun setContentTextColors( normalModeColor: ColorStateList?, highContrastModeColor: ColorStateList? ) { setTPTextViewColors(content as TPTextView, normalModeColor, highContrastModeColor) } fun setTagTextColors(normalModeColor: ColorStateList?, highContrastModeColor: ColorStateList?) { setTPTextViewColors(tag as TPTextView, normalModeColor, highContrastModeColor) } fun setContentText(@StringRes resId: Int) { content.setText(resId) content.visibility = if (content.text == null || content.text.isEmpty()) GONE else VISIBLE } fun setContentText(contentText: String?) { content.text = contentText content.visibility = if (contentText == null || contentText.isEmpty()) GONE else VISIBLE } fun setContentText(contentText: CharSequence?) { content.text = contentText content.visibility = if (contentText == null || contentText.isEmpty()) GONE else VISIBLE } fun setLabelText(@StringRes resId: Int) { label.setText(resId) label.visibility = if (label.text == null || label.text.isEmpty()) GONE else VISIBLE } fun setLabelText(labelText: String?) { label.text = labelText label.visibility = if (labelText == null || labelText.isEmpty()) GONE else VISIBLE } fun setLabelText(labelText: CharSequence?) { label.text = labelText label.visibility = if (labelText == null || labelText.isEmpty()) GONE else VISIBLE } fun setTagText(@StringRes resId: Int) { tag.setText(resId) tag.visibility = if (tag.text == null || tag.text.isEmpty()) GONE else VISIBLE } fun setTagText(tagText: String?) { tag.text = tagText tag.visibility = if (tagText == null || tagText.isEmpty()) GONE else VISIBLE } fun setTagText(tagText: CharSequence?) { tag.text = tagText tag.visibility = if (tagText == null || tagText.isEmpty()) GONE else VISIBLE } override fun getItemContentDescription(): String { var result = "" //标题 getContentDescriptionOrText(getTitle())?.toString()?.let { result = mergeStringsForA11y(result, it, isBlank = true) } //label getContentDescriptionOrText(label)?.toString()?.let { if (it.isNotEmpty()){ result = mergeStringsForA11y(result, it) } } //content getContentDescriptionOrText(content)?.toString()?.let { if (it.isNotEmpty()){ result = mergeStringsForA11y(result, it) } } //tag getContentDescriptionOrText(tag)?.toString()?.let { if (it.isNotEmpty()){ result = mergeStringsForA11y(result, it) } } //若末尾的loadingView或checkbox、radioButton、switch处于loading状态,均视为Processing if (getActionLoading().isVisible || getActionCheckbox().isStateLoading() || getActionRadio().isStateLoading() || getActionSwitch().isStateLoading()) { result = mergeStringsForA11y(result, context.getString(R.string.tpds_progressing)) } return result } }可以給這個結構的tag設置一個紅點標志的圖標嗎
最新发布
11-28
### 代码作用 `filterParameter.getType() == XmlRpc::XmlRpcValue::TypeArray` 这行代码主要用于检查 `filterParameter` 这个 `XmlRpc::XmlRpcValue` 对象的类型是否为数组类型。`filterParameter.getType()` 是调用 `XmlRpcValue` 类的 `getType()` 方法,该方法会返回一个表示 `XmlRpcValue` 对象类型的值。`XmlRpc::XmlRpcValue::TypeArray` 是 `XmlRpcValue` 类中定义的一个常量,代表数组类型。如果 `filterParameter` 是数组类型,该表达式返回 `true`,否则返回 `false`。 ### 使用场景 在处理 XML-RPC(一种远程过程调用协议)数据时,经常需要根据数据的类型进行不同的处理。例如,当从 XML-RPC 服务器接收到一个 `XmlRpcValue` 对象时,可能不清楚其具体类型,需要先判断它是否为数组类型,再决定如何进一步处理。以下是一个简单的示例代码: ```cpp #include <XmlRpc.h> #include <iostream> void processXmlRpcValue(XmlRpc::XmlRpcValue filterParameter) { if (filterParameter.getType() == XmlRpc::XmlRpcValue::TypeArray) { // 处理数组类型的数据 for (int i = 0; i < filterParameter.size(); ++i) { std::cout << "Array element " << i << ": " << filterParameter[i] << std::endl; } } else { // 处理其他类型的数据 std::cout << "Not an array. Value: " << filterParameter << std::endl; } } int main() { XmlRpc::XmlRpcValue arrayValue; arrayValue[0] = 1; arrayValue[1] = 2; arrayValue[2] = 3; processXmlRpcValue(arrayValue); return 0; } ``` ### 可能出现的问题及解决方案 #### 1. 类型判断错误 问题:由于 `XmlRpcValue` 可能有多种类型,可能会因为判断条件不准确导致处理逻辑错误。 解决方案:在进行类型判断时,要确保考虑到所有可能的类型,并进行相应的处理。可以使用 `switch` 语句或者多个 `if-else` 语句来处理不同类型。 #### 2. 空指针异常 问题:如果 `filterParameter` 是一个空指针,调用 `getType()` 方法会导致空指针异常。 解决方案:在调用 `getType()` 方法之前,先检查 `filterParameter` 是否为空指针。示例代码如下: ```cpp if (filterParameter.valid()) { if (filterParameter.getType() == XmlRpc::XmlRpcValue::TypeArray) { // 处理数组类型的数据 } else { // 处理其他类型的数据 } } else { std::cout << "filterParameter is not valid." << std::endl; } ``` #### 3. 数组越界访问 问题:在处理数组类型的数据时,如果不小心访问了超出数组范围的元素,会导致数组越界访问错误。 解决方案:在访问数组元素之前,先检查数组的大小,确保访问的索引在有效范围内。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值