72

I wrote a custom view that extends RelativeLayout. My view has text, so I want to use the standard android:text without the need to specify a <declare-styleable> and without using a custom namespace xmlns:xxx every time I use my custom view.

this is the xml where I use my custom view:

<my.app.StatusBar
    android:id="@+id/statusBar"
    android:text="this is the title"/>

How can I get the attribute value? I think I can get the android:text attribute with

TypedArray a = context.obtainStyledAttributes(attrs,  ???);

but what is ??? in this case (without a styleable in attr.xml)?

sebkur
  • 658
  • 2
  • 9
  • 18
Seraphim's
  • 12,559
  • 20
  • 88
  • 129

2 Answers2

111

use this:

public YourView(Context context, AttributeSet attrs) {
    super(context, attrs);
    int[] set = {
        android.R.attr.background, // idx 0
        android.R.attr.text        // idx 1
    };
    TypedArray a = context.obtainStyledAttributes(attrs, set);
    Drawable d = a.getDrawable(0);
    CharSequence t = a.getText(1);
    Log.d(TAG, "attrs " + d + " " + t);
    a.recycle();
}

i hope you got an idea

pskink
  • 23,874
  • 6
  • 66
  • 77
  • 3
    i used same thing but it seems like not working for some attributes like 'textColor'. do you have any idea? – eluleci Jan 28 '14 at 09:38
  • @pskink what's you thoughts about http://stackoverflow.com/questions/24650879/magic-with-obtainstyledattributes-method ? – AlexKorovyansky Jul 09 '14 at 10:25
  • 2
    One question. Since that reused attribute doesn't belong to a custom view (in this case android:text doesn't belong to RelativeLayout) it is not showing in 'suggestions' in IDE (Android Studio in my case) when declaring the custom view in XML. Is there a way to make android:text appear in suggestions as well so user knows this is also available attribute in the view? – vir us Apr 18 '15 at 12:04
  • 2
    This does not work anymore, at least in my version of Android Studio (2.2). When trying to call `getText(1)` on the `TypedArray` with a plain `int`, the inspection complains: "Expected resource of type styleable". Using `getText()` with something like `R.styleable.MyCustomView_android_text` works however. I guess Android Studio became "smarter" – sebkur Feb 19 '17 at 17:46
  • @sebkur did you actually run the code? if so, what does `getText()` return? – pskink Feb 19 '17 at 17:48
  • Ah, I see, it does compile even though Android Studio underlines it with a snaky red line. Mistook this for an actual compile error. – sebkur Feb 19 '17 at 22:34
  • This is great idea, but if I need to obtain both marginTop and marginBottom, for example - it would take only first-indexed value correctly, other will be 0. – Goltsev Eugene Apr 17 '18 at 09:53
49

EDIT

Another way to do it (with specifying a declare-styleable but not having to declare a custom namespace) is as follows:

attrs.xml:

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

MyCustomView.java:

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView);
CharSequence t = a.getText(R.styleable.MyCustomView_android_text);
a.recycle();

This seems to be the generic Android way of extracting standard attributes from custom views.

Within the Android API, they use an internal R.styleable class to extract the standard attributes and don't seem to offer other alternatives of using R.styleable to extract standard attributes.

Original Post

To ensure that you get all the attributes from the standard component, you should use the following:

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextView);
CharSequence t = a.getText(R.styleable.TextView_text);
int color = a.getColor(R.styleable.TextView_textColor, context.getResources().getColor(android.R.color.darker_gray)); // or other default color
a.recycle();

If you want attributes from another standard component just create another TypedArray.

See http://developer.android.com/reference/android/R.styleable.html for details of available TypedArrays for standard components.

J. Beck
  • 746
  • 6
  • 11
  • ':' is not a valid resource name character. damn it. – Oleksandr Nos Dec 22 '15 at 13:58
  • 1
    @SashaNos. The ':' is used in XML but for the resource name in code use '_' in place of it. See the difference in the post. I'll delete the original post if it is confusing or unhelpful – J. Beck Dec 22 '15 at 15:36
  • yes, I understand the difference. Android Studio just doesn't accept this name `` because of colon :( – Oleksandr Nos Dec 22 '15 at 15:43
  • It does. I am using `android:orientation` in one of my projects now. However, you may need to ensure that you are using the correct attribute name. The list of valid names is listed in the [attribute reference](http://developer.android.com/reference/android/R.attr.html). – J. Beck Dec 22 '15 at 16:10
  • @J.Beck I get the same error as your do with the colon – Christopher Rucinski Jan 14 '16 at 14:50
  • This is weird... Maybe it's a bug? What platform are you guys using? I use Windows 10 with the latest version of Android Studio. – J. Beck Jan 15 '16 at 16:51
  • I used `` and it always went to compile error "android:text is already defined". Changing to `` works, OMG. – Weekend Aug 03 '18 at 03:34
  • Finally, I found the reason why I can't specify `format="string"`. It's a limitation of old version gradle plugin. On `classpath 'com.android.tools.build:gradle:2.3.3'`, it will end up with a compile error; On `classpath 'com.android.tools.build:gradle:3.1.3'`, it compiles well. – Weekend Aug 03 '18 at 06:26
  • 1
    This should be the accepted answer. It requires minimal change to existing code and reads a lot cleaner. – Melllvar Feb 15 '19 at 19:14