66

I create programmatically like horizontalview then, how to pass AttributeSet in programmatically.

My constructor looks like this:

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

I have try this:

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

Error:

The constructor HorizontalListView(Context, int) is undefined

in style.xml

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

</style>

How to pass AttributeSet in horizontalistview constructor matching parameter?

olfek
  • 3,210
  • 4
  • 33
  • 49
Bixms
  • 771
  • 1
  • 7
  • 16
  • https://stackoverflow.com/a/25457076/1105214 – samus Mar 05 '18 at 20:12
  • I'm finding it easiest to simply make a layout for a custom view and inflate it, and if you have multiple instances that differ slightly, just make a base style and sub-class it with ` – samus Mar 05 '18 at 20:36

4 Answers4

47

The constructor with Context and AttributeSet is used when your view is inflated from xml. You shouldn't use it to create object. You should use constructor with Context as param.

AttributeSet is interface and you can create instance of then and implement all method as is shown below:

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;
        }
    }; 

And use it

TextView textView = new TextView(this, attrs);

but it is not correct way.

You should use methods from your view to set properties of view.

For example to set LayoutParams is two way to do this

First by method setLayoutParams()

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

The second when you added your view to ViewGroup;

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

When you have or you want to add your view to for example to RelativeLayout you should use LayoutParams relevant for this ViewGroup. It is RelativeLayout.LayoutParams

Konrad Krakowiak
  • 12,285
  • 11
  • 58
  • 45
  • 3
    My concern, how to pass AttributeSet in constructor in android. – Bixms Mar 13 '15 at 09:00
  • you shouldn't do this the constructor with two params is used by creator when you create your view in xml – Konrad Krakowiak Mar 13 '15 at 09:01
  • 2
    If you want to create your object manually you have to use constructor with `Context` as params and set your properties by methods. – Konrad Krakowiak Mar 13 '15 at 09:02
  • 4
    But in Horizontal Constructore is accept two paramter one in context and ohter is AttributeSet, so that, How to create HorizontalListView view programmtically in the absence of attrs, but it takes attrs paramter. – Bixms Mar 13 '15 at 09:14
  • All Views have four constructors (it is depends of a API Level) and all have public access But all of them have specific goal and specification where should be used – Konrad Krakowiak Mar 13 '15 at 09:18
  • Does my answer explain you your issue? – Konrad Krakowiak Mar 13 '15 at 09:32
  • How about the scenario where you want to espresso test a custom View in isolation, which expects attributes to modify its behavior. By creating setters to set the values that would be set by attributes then you're kinda skipping part of the test and adding code just for the test scenario – darnmason Aug 25 '17 at 02:31
  • 4
    Your own implementation of AttributeSet interface will not work. Android will throw java.lang.ClassCastException: cannot be cast to android.content.res.XmlBlock$Parser – Gena Batsyan Dec 01 '19 at 06:52
27

i have a way to get the AttributeSet from a xml file.

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();

if the count value is bigger than 0, then means you get a right AttributeSet.

my xml/test.xml is like these:

<?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" />
SDJSK
  • 1,292
  • 17
  • 24
  • I'm still new to this android development thing. Why isn't this the accepted answer? This seems to make boatloads of sense.... – HumbleWebDev Sep 07 '17 at 17:50
  • 1
    @HumbleWebDev B/c there really isn't a need to re-implement functionality that the framework already provides - `MyListView` is already in a layout file, so the inflating of it will pass in the attribute set to it's "inflation" constructor (`MyListView(Context c, AttributeSet a`). I can't really think of any other use for this besides some hacking of the framework, but could be wrong. – samus Mar 05 '18 at 19:57
  • 1
    @HumbleWebDev The framework hides this kind of code away in private methods for a good reason - so that users are abstracted away from it's implementation. The more of these snippets an app has the less backward compatible and more fragile it becomes. – samus Mar 05 '18 at 20:14
  • 4
    This should be the ACCEPTED ANSWER! – Bahaa Ibrahim Jul 21 '19 at 00:01
  • 1
    It happens in Android that you can set an attribute in XML, but there is no equivalent setter/getter on the class itself. So if you're creating the view/preference in code then you're stuck. An example is allowDividerBelow in Preference. – pallgeuer Mar 13 '21 at 13:18
  • If you're going to use XML to solve this, why not just inflate the whole view from XML using something like this: https://stackoverflow.com/a/23592361/191761 – Adam Burley Aug 18 '22 at 14:15
  • This worked great! We're using a 3rd party custom view that needs to be inserted after layout...so just added the xml in a separate file and used it when calling their custom_view(context, attributes) constructor. Thanks a million! – Mike Critchley Feb 20 '23 at 09:49
2

I ran into this question while working with a view that forgot to implement the SomeView(Context) constructor and only had the one with SomeView(Context, AttributeSet) available. From the source code of ViewGroup it appears that SomeView(context) would be equivalent to SomeView(context, null), though.

Elte Hupkes
  • 2,773
  • 2
  • 23
  • 18
-5

You can create an attribute referencing a custom style. Then you should be able to instantiate it using

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

A full example is available there https://gist.github.com/romannurik/7026222

John
  • 601
  • 5
  • 8
  • That gist shows the 3 param ctor being used `View(Context, AttributeSet, int)` where `R.attr.niceview` is the attribute that points to the default style – ataulm Mar 06 '17 at 14:48