在Android中以编程方式创建视图时如何传递AttributeSet

67

我想以编程方式创建类似HorizontalView这样的控件,那么如何在代码中传递AttributeSet参数。

我的构造函数如下所示:

public HorizontalListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

我尝试了这个:

mHlvSimpleList= new HorizontalListView(mcontext,R.style.niceview);

错误:

构造函数 HorizontalListView(Context, int) 未定义

在 style.xml 中。

<style name="niceview">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>

</style>

如何在HorizontalistView构造函数中传递匹配参数的AttributeSet?


https://dev59.com/MGYr5IYBdhLWcg3wYZSD#25457076 - samus
我发现最简单的方法是为自定义视图创建一个布局并进行填充,如果您有多个略有不同的实例,只需创建一个基本样式并使用<style="AutoDroid" parent="Droid"><style="DeceptaDroid" parent="Droid">进行子类化。 - samus
4个回答

49

当您的视图从xml中膨胀时,使用具有ContextAttributeSet的构造函数。您不应该使用它来创建对象。您应该使用带有Context作为参数的构造函数。

AttributeSet是接口,您可以创建它的实例并按照下面所示实现所有方法:

AttributeSet attrs = new AttributeSet(){
        @Override
        public int getAttributeCount() {
            return 0;
        }

        @Override
        public String getAttributeName(int index) {
            return null;
        }

        @Override
        public String getAttributeValue(int index) {
            return null;
        }

        @Override
        public String getAttributeValue(String namespace, String name) {
            return null;
        }

        @Override
        public String getPositionDescription() {
            return null;
        }

        @Override
        public int getAttributeNameResource(int index) {
            return 0;
        }

        @Override
        public int getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue) {
            return 0;
        }

        @Override
        public boolean getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue) {
            return false;
        }

        @Override
        public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
            return 0;
        }

        @Override
        public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
            return 0;
        }

        @Override
        public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
            return 0;
        }

        @Override
        public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
            return 0;
        }

        @Override
        public int getAttributeListValue(int index, String[] options, int defaultValue) {
            return 0;
        }

        @Override
        public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
            return false;
        }

        @Override
        public int getAttributeResourceValue(int index, int defaultValue) {
            return 0;
        }

        @Override
        public int getAttributeIntValue(int index, int defaultValue) {
            return 0;
        }

        @Override
        public int getAttributeUnsignedIntValue(int index, int defaultValue) {
            return 0;
        }

        @Override
        public float getAttributeFloatValue(int index, float defaultValue) {
            return 0;
        }

        @Override
        public String getIdAttribute() {
            return null;
        }

        @Override
        public String getClassAttribute() {
            return null;
        }

        @Override
        public int getIdAttributeResourceValue(int defaultValue) {
            return 0;
        }

        @Override
        public int getStyleAttribute() {
            return 0;
        }
    }; 

并使用它

TextView textView = new TextView(this, attrs);

这并不是正确的方法

你应该使用视图中的方法来设置视图的属性。

例如,设置LayoutParams有两种方法:

第一种是使用setLayoutParams()方法。

view.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

当您将视图添加到ViewGroup时的那一刻;

viewGroup.addView(yourView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

当您拥有或希望将视图添加到例如RelativeLayout中时,应使用与此ViewGroup相关的LayoutParams。它是RelativeLayout.LayoutParams


4
我的关注点是如何在安卓中的构造函数中传递AttributeSet。 - Bixms
不应该这样做,带有两个参数的构造函数是由创建者在XML中创建视图时使用的。 - Konrad Krakowiak
2
如果您想手动创建对象,则必须使用带有“Context”参数的构造函数,并通过方法设置属性。 - Konrad Krakowiak
4
但在Horizontal Constructor中接受两个参数,一个是context,另一个是AttributeSet。那么,在没有属性的情况下如何通过编程方式创建HorizontalListView视图,但它需要一个属性参数。 - Bixms
4
您自己实现的AttributeSet接口将无法工作。Android会抛出java.lang.ClassCastException异常:<您的实现类>无法转换为android.content.res.XmlBlock$Parser。 - Gena Batsyan
显示剩余3条评论

27

我有一种方法可以从xml文件中获取AttributeSet。

XmlPullParser parser = getResources().getXml(R.xml.test);
        try {
            parser.next();
            parser.nextTag();
        } catch (Exception e) {
            e.printStackTrace();
        }

        AttributeSet attr = Xml.asAttributeSet(parser);
        int count = attr.getAttributeCount();

如果计数值大于0,则表示您获得了正确的AttributeSet。

我的xml/test.xml文件如下:

<?xml version="1.0" encoding="utf-8"?>
<com.galoisli.myapplication.MyListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/listView"
    android:scrollbarThumbVertical="@drawable/scrollbar_vertical_thumb"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true" />

1
@HumbleWebDev 因为框架已经提供了功能,所以没有必要重新实现 - MyListView 已经在布局文件中,因此将其膨胀的时候会传递属性集到它的“膨胀”构造函数 (MyListView(Context c, AttributeSet a))。我真的想不出除了对框架进行一些黑客攻击之外还有什么其他用途,但可能是我错了。 - samus
1
@HumbleWebDev 框架将这种代码隐藏在私有方法中,有很好的理由 - 这样用户就可以从其实现中抽象出来。应用程序拥有更多这些片段,它就变得越不向后兼容,越脆弱。 - samus
4
这应该是被接受的答案! - Bahaa Ibrahim
1
在Android中,有时你可以在XML中设置一个属性,但是类本身没有相应的setter/getter。因此,如果你正在代码中创建视图/首选项,则会遇到困难。Preference中的allowDividerBelow就是一个例子。 - pallgeuer
如果您要使用XML来解决这个问题,为什么不直接使用类似于以下链接中的代码从XML中填充整个视图:https://dev59.com/wH_aa4cB1Zd3GeqP45Ph#23592361 - Adam Burley
显示剩余2条评论

2

我在使用一个视图时遇到了这个问题,该视图忘记实现 SomeView(Context) 构造函数,只有 SomeView(Context, AttributeSet) 可用。根据 ViewGroup 的源代码,似乎 SomeView(context) 等同于 SomeView(context, null)


-5

您可以创建一个引用自定义样式的属性。然后,您应该能够使用它进行实例化。

mHlvSimpleList= new HorizontalListView(mcontext, R.attr.niceview);

这里有一个完整的示例 https://gist.github.com/romannurik/7026222


该代码片段展示了使用View(Context, AttributeSet, int)构造函数的三个参数,其中R.attr.niceview是指向默认样式的属性。 - ataulm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接