Asked  7 Months ago    Answers:  5   Viewed   42 times

I need to implement my own attributes like in com.android.R.attr

Found nothing in official documentation so I need information about how to define these attrs and how to use them from my code.

 Answers

49

Currently the best documentation is the source. You can take a look at it here (attrs.xml).

You can define attributes in the top <resources> element or inside of a <declare-styleable> element. If I'm going to use an attr in more than one place I put it in the root element. Note, all attributes share the same global namespace. That means that even if you create a new attribute inside of a <declare-styleable> element it can be used outside of it and you cannot create another attribute with the same name of a different type.

An <attr> element has two xml attributes name and format. name lets you call it something and this is how you end up referring to it in code, e.g., R.attr.my_attribute. The format attribute can have different values depending on the 'type' of attribute you want.

  • reference - if it references another resource id (e.g, "@color/my_color", "@layout/my_layout")
  • color
  • boolean
  • dimension
  • float
  • integer
  • string
  • fraction
  • enum - normally implicitly defined
  • flag - normally implicitly defined

You can set the format to multiple types by using |, e.g., format="reference|color".

enum attributes can be defined as follows:

<attr name="my_enum_attr">
  <enum name="value1" value="1" />
  <enum name="value2" value="2" />
</attr>

flag attributes are similar except the values need to be defined so they can be bit ored together:

<attr name="my_flag_attr">
  <flag name="fuzzy" value="0x01" />
  <flag name="cold" value="0x02" />
</attr>

In addition to attributes there is the <declare-styleable> element. This allows you to define attributes a custom view can use. You do this by specifying an <attr> element, if it was previously defined you do not specify the format. If you wish to reuse an android attr, for example, android:gravity, then you can do that in the name, as follows.

An example of a custom view <declare-styleable>:

<declare-styleable name="MyCustomView">
  <attr name="my_custom_attribute" />
  <attr name="android:gravity" />
</declare-styleable>

When defining your custom attributes in XML on your custom view you need to do a few things. First you must declare a namespace to find your attributes. You do this on the root layout element. Normally there is only xmlns:android="http://schemas.android.com/apk/res/android". You must now also add xmlns:whatever="http://schemas.android.com/apk/res-auto".

Example:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:whatever="http://schemas.android.com/apk/res-auto"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">

    <org.example.mypackage.MyCustomView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:gravity="center"
      whatever:my_custom_attribute="Hello, world!" />
</LinearLayout>

Finally, to access that custom attribute you normally do so in the constructor of your custom view as follows.

public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);

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

  String str = a.getString(R.styleable.MyCustomView_my_custom_attribute);

  //do something with str

  a.recycle();
}

The end. :)

Tuesday, June 1, 2021
 
e_i_pi
answered 7 Months ago
12

use this code

select.xml in drawable folder

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >

        <solid android:color="#ffffff" >
        </solid>

        <stroke
            android:width="2dp"
            android:color="#ff0000" >
        </stroke>
<corners android:radius="5dp" />

    <padding
        android:bottom="4dp"
        android:left="4dp"
        android:right="4dp"
        android:top="4dp" />
    </shape>

deselect.xml in drawable folder

 <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >

        <solid android:color="#ffffff" >
        </solid>

        <stroke
            android:width="2dp"
            android:color="#000000" >
        </stroke>
    <corners android:radius="5dp" />

    <padding
        android:bottom="4dp"
        android:left="4dp"
        android:right="4dp"
        android:top="4dp" />
    </shape>

and custom checkbox

public class checkbox extends CheckBox{



    public checkbox(Context context, AttributeSet attrs) {
            super(context, attrs);
            //setButtonDrawable(new StateListDrawable());
        }
        @Override
        public void setChecked(boolean t){
            if(t)
            {
                this.setBackgroundResource(R.drawable.select);
            }
            else
            {
                this.setBackgroundResource(R.drawable.deselect);
            }
            super.setChecked(t);
        }
        }

checkbox

 <com.example.checkbox.checkbox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:button="@null"
        android:checked="true"
        android:text="checked" />

you can change color in select.xml and deselect.xml to thing that you want

Wednesday, July 28, 2021
 
Akarun
answered 5 Months ago
45

If the folders are included in the Project Build Path, you can use ClassLoader access files under them outside the android.content.Context, for instance, from a POJO (in case if you don't want to pass a reference of android.content.Context):

String file = "res/raw/test.txt";
InputStream in = this.getClass().getClassLoader().getResourceAsStream(file);
  • The res folder is included into Project Build Path by default by all Android SDK version so far.
  • The assets folder was included into Project Build Path by default before Android SDK r14.

To add folders into Project Build Path, right click your project -- Build Path -- Configure Build Path, add your folder (for example, assets if using later SDK version) as a Source folder in build path.

Check out the similar question I answered before at here.

Thursday, August 5, 2021
 
Simmeringc
answered 4 Months ago
71

Looking at the source code of the two methods, they seem very similar. If you don't have vectors, you could probably get away with using either one or the other.

ResourcesCompat.getDrawable() will call Resources#getDrawable(int, theme) on APIs 21 or greater. It also supports Android APIs 4+. It is no more than this:

public Drawable getDrawable(Resources res, int id, Theme theme)
        throws NotFoundException {
    final int version = Build.VERSION.SDK_INT;
    if (version >= 21) {
        return ResourcesCompatApi21.getDrawable(res, id, theme);
    } else {
        return res.getDrawable(id);
    }
}

Where-in ResourcesCompatApi21 merely calls res.getDrawable(id, theme). This means it will not allow vector drawables to be drawn if the device does not support vector drawables. It will, however, allow you to pass in a theme.

Meanwhile, the code change for AppCompatResources.getDrawable(Context context, int resId) eventually lands to this:

Drawable getDrawable(@NonNull Context context, @DrawableRes int resId, boolean failIfNotKnown) {
    checkVectorDrawableSetup(context);

    Drawable drawable = loadDrawableFromDelegates(context, resId);
    if (drawable == null) {
        drawable = createDrawableIfNeeded(context, resId);
    }
    if (drawable == null) {
        drawable = ContextCompat.getDrawable(context, resId);
    }

    if (drawable != null) {
        // Tint it if needed
        drawable = tintDrawable(context, resId, failIfNotKnown, drawable);
    }
    if (drawable != null) {
        // See if we need to 'fix' the drawable
        DrawableUtils.fixDrawable(drawable);
    }

    return drawable;
}

So this instance it will attempt to draw the resource if it can, otherwise it looks in the ContextCompat version to get the resource. Then it will even tint it if necessary. However, this method only supports API 7+.

So I guess to decide if you should use either,

  1. Do you have to support API 4, 5, or 6?

    • Yes: No choice but to use ResourcesCompat or ContextCompat.
    • No: Keep going to #2.
  2. Do you absolutely need to supply a custom Theme?

    • Yes: No choice but to use ResourcesCompat
    • No: Use AppCompatResources
Sunday, August 8, 2021
 
panthro
answered 4 Months ago
22

Those functions should be declared as an operator () in a class, unfortunately. Like this:

class VertexSetHashFunction {
  public:
    ::std::size_t operator ()(const ::std::set<Vertex3DXT*> &vertexSet) const;
};
class SetEqual {
  public:
    bool operator ()(const ::std::set<Vertex3DXT*> &a, const ::std::set<Vertex3DXT*> &b) const;
};

You do not have to modify the arguments to be const references, but I would highly recommend it. Making a copy of a ::std::set is relatively expensive and you shouldn't do it unless you absolutely have to.

The trailing const is just because the operator doesn't actually modify the class state at all, mostly because there isn't any. It's just nice to say so explicitly.

Alternately, you could define your own specialization of the ::std::hash template. I would actually recommend this if there is one standard way you want that particular set hashed because this template is used by default if you do not supply a hash function to unordered_map or unordered_set and anything else that needs a hash function.

Tuesday, August 10, 2021
 
Shreejibawa
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share