英文:
Android custom attributes return null
问题
我正在尝试学习如何在Android Studio中使用自定义属性。我按照一些关于这个主题的教程进行操作,尽管我努力了,但似乎什么都不起作用。我创建了一个能够说明问题的代码。
我创建了一个简单的自定义视图,它不代表任何内容,只是获取了一些样式化的属性。这是我的customView代码:
package com.example.mytestattributes;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
public class customView extends View {
public customView(Context context) {
super(context);
init(null);
}
public customView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(@Nullable AttributeSet attrs){
if(attrs!=null){
Log.d("INIT", "找到属性集");
TypedArray ta = getContext().obtainStyledAttributes(R.styleable.customView);
Log.d("TA的长度:", ta.length()+"");
Log.d("testString 有值吗:", ta.hasValue(R.styleable.customView_testString)+"");
Log.d("testInteger 有值吗:", ta.hasValue(R.styleable.customView_testInteger)+"");
Log.d("testBoolean 有值吗:", ta.hasValue(R.styleable.customView_testBoolean)+"");
Log.d("testColor 有值吗:", ta.hasValue(R.styleable.customView_testColor)+"");
Log.d("testDimension 有值吗:", ta.hasValue(R.styleable.customView_testDimension)+"");
Log.d("testEnum 有值吗:", ta.hasValue(R.styleable.customView_testEnum)+"");
Log.d("返回 testDimension:", ""+ta.getDimensionPixelSize(R.styleable.customView_testDimension,0));
Log.d("返回 testDimension:", ""+ta.getDimension(R.styleable.customView_testDimension,0));
}else{
Log.d("INIT", "未找到属性集");
}
}
}
代码编译后的输出如下:
D/INIT: 找到属性集
D/TA的长度: 6
D/testString 有值吗: false
D/testInteger 有值吗: false
D/testBoolean 有值吗: false
D/testColor 有值吗: false
D/testDimension 有值吗: false
D/testEnum 有值吗: false
D/返回 testDimension: 0
D/返回 testDimension: 0.0
TypedArray的长度是正确的,这意味着程序看到了属性,但是当我询问属性是否有值时,结果却是false。因此,任何尝试读取这些属性的操作都会返回默认值。在示例代码中,我只包含了getDimension方法,但是对于所有其他的get方法也是一样的。
这是我的attrs.xml,其中我定义了这些属性:
<resources>
<declare-styleable name="customView">
<attr name="testString" format="string|reference"/>
<attr name="testInteger" format="integer"/>
<attr name="testBoolean" format="boolean"/>
<attr name="testColor" format="color|reference"/>
<attr name="testDimension" format="dimension"/>
<attr name="testEnum" format="enum">
<enum name="var1" value="1"/>
<enum name="var2" value="2"/>
</attr>
</declare-styleable>
</resources>
我试图在Activity_Main.xml中传递值:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.mytestattributes.customView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:testBoolean="true"
app:testDimension="200dp"
app:testColor="@color/colorAccent"
app:testEnum="var1"
app:testInteger="15"
app:testString="@string/app_name"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java是未经修改的空活动类。我知道一些人在几年前遇到过类似的问题,但从来没有发布过有效的答案。有人知道这段代码有什么问题吗?我使用的是API 17。
英文:
I'm trying to learn how to use custom attributes in Android Studio. I follow a couple of tutorials on the subject and despite my efforts nothing seems to work. I created a code that illustrates the problem.
I've created simple custom view, which doesnt represent anything but only obtains styled attributes. This is my customView code:
package com.example.mytestattributes;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.Nullable;
public class customView extends View {
public customView(Context context) {
super(context);
init(null);
}
public customView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(@Nullable AttributeSet attrs){
if(attrs!=null){
Log.d("INIT", "attribute set found");
TypedArray ta = getContext().obtainStyledAttributes(R.styleable.customView);
Log.d("LENGHT OF TA: ", ta.length()+"");
Log.d("testString has value", ta.hasValue(R.styleable.customView_testString)+"");
Log.d("testInteger has value", ta.hasValue(R.styleable.customView_testInteger)+"");
Log.d("testBoolean has value", ta.hasValue(R.styleable.customView_testBoolean)+"");
Log.d("testColor has value", ta.hasValue(R.styleable.customView_testColor)+"");
Log.d("testDimension has value", ta.hasValue(R.styleable.customView_testDimension)+"");
Log.d("testEnum has value", ta.hasValue(R.styleable.customView_testEnum)+"");
Log.d("Return testDimension: ", ""+ta.getDimensionPixelSize(R.styleable.customView_testDimension,0));
Log.d("Return testDimension: ", ""+ta.getDimension(R.styleable.customView_testDimension,0));
}else{
Log.d("INIT", "no attribute set found");
}
}
}
The code compiles and the output is:
D/INIT: attribute set found
D/LENGHT OF TA:: 6
D/testString has value: false
D/testInteger has value: false
D/testBoolean has value: false
D/testColor has value: false
D/testDimension has value: false
D/testEnum has value: false
D/Return testDimension:: 0
D/Return testDimension:: 0.0
The lenght of typed array is correct, meaning that the program sees the attributes but when I ask it to check if the attributes have value the outcome is false. As a consequence any attempt to read this attibutes always returns default value. In the example code I included just getDimension but the same holds for all other get methods.
This is my attrs.xml, where I defined the attibutes:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="customView">
<attr name="testString" format="string|reference"/>
<attr name="testInteger" format="integer"/>
<attr name="testBoolean" format="boolean"/>
<attr name="testColor" format="color|reference"/>
<attr name="testDimension" format="dimension"/>
<attr name="testEnum" format="enum">
<enum name="var1" value="1"/>
<enum name="var2" value="2"/>
</attr>
</declare-styleable>
</resources>
I try to pass values in Activity_Main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.mytestattributes.customView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:testBoolean="true"
app:testDimension="200dp"
app:testColor="@color/colorAccent"
app:testEnum="var1"
app:testInteger="15"
app:testString="@string/app_name"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
The MainActivity.java is unmodified empty activity class.
I am aware that some people had the similiar problems a couple of years ago but no valid answers were ever posted.
Is anyone aware what is wrong with this code?
Im using API 17.
答案1
得分: 3
经过一些调试,我用以下代码替换了这行:
TypedArray ta = getContext().obtainStyledAttributes(R.styleable.customView);
替换为
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.customView);
问题得以解决。
此外,我还发现如果TypedArray再次出问题,也可以直接从attrs中获取值,使用以下方式:
attrs.getValue(int index)
需要注意的是,在属性集中的属性索引与类型化数组中的索引不同,因为它还包括了标准的Android属性。可以使用以下代码检查索引:
for (int i = 0; i < attrs.getAttributeCount(); i++) {
Log.d("ATTRS", i + ": " + attrs.getAttributeName(i) + "");
}
英文:
After some tinkering I replaced the line:
TypedArray ta = getContext().obtainStyledAttributes(R.styleable.customView);
with
TypedArray ta = getContext().obtainStyledAttributes(attrs,R.styleable.customView);
and the problem was solved.
Alternatively I also found out that if the TypedArray ever failed me again it is possible to get values directly from attrs, with:
attrs.getValue(int index)
It must be noted that the index of the attribute in the attribute set is different than the index in the typed array, as it includes also standard android attributes. The index can be checked with:
for (int i = 0; i < attrs.getAttributeCount(); i++) {
Log.d("ATTRS", i+ ": " + attrs.getAttributeName(i)+"");
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论