6

I'm trying to create a custom attribute that behaves like tools:context, that is with

  • Android Studio auto complete functionallity
  • Project classname reference
  • Support for auto refactory in case I change my class directory

This is my resources.xml

<declare-styleable name="RecyclerView">
    <attr name="adapter" format="string"></attr>
</declare-styleable>

This is the usage

    <example.com.br.appname.RecyclerView
         android:id="@+id/accounts"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_marginTop="8dp"
         app:adapter="example.com.br.appname.AccountAdapter" >
    </example.com.br.appname.RecyclerView>

I've tried to use the format reference but it didn't compile as well.

Error:(17, 22) String types not allowed (at 'adapter' with value 'example.com.br.appname.AccountAdapter').

2 Answers 2

2

I don’t think this is possible currently. Other similar custom attrs I can think of, for instance app:layout_behavior from the design library, or simply app:layoutManager from RecyclerView all require the full classname, with none of your requirements.

It might be better to store these in a strings resource file, and remember to check it when refactoring class names.

You can consider filing a feature request, since Android Studio has this functionality in special cases (tools:context, class in <view> and <fragment> tags, classes in Manifest...), but I doubt they would add a new attribute format just for this.

Sign up to request clarification or add additional context in comments.

2 Comments

Well ... I think I will need to give up doing it this way ... Maybe I will need to do it programmatically and not in the layout file ... that is sad :(
If this is for your own app (not a library) and you have a reasonably small amount of adapters, you could use a enum attribute (for example, FloatingActionButton has an enum for size, mini and normal) enumerating all your adapters with short names.
2

so...

  • apparently, YOU CAN!
  • Google does this too.
  • Android Studio understands that the class is being referenced from XML
    • i.e.
      • Refactor > Rename works
      • Find Usages works
      • and so on...

don't specify a format attribute in .../src/main/res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="MyCustomView">
        ....
        <attr name="give_me_a_class"/>
        ....
    </declare-styleable>

</resources>

use it in some layout file .../src/main/res/layout/activity__main_menu.xml

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

    <!-- make sure to use $ dollar signs for nested classes -->
    <MyCustomView
        app:give_me_a_class="class.type.name.Outer$Nested/>

    <MyCustomView
        app:give_me_a_class="class.type.name.AnotherClass/>

</SomeLayout>

parse the class in your view initialization code .../src/main/java/.../MyCustomView.kt

class MyCustomView(
        context:Context,
        attrs:AttributeSet)
    :View(context,attrs)
{
    // parse XML attributes
    ....
    private val giveMeAClass:SomeCustomInterface
    init
    {
        context.theme.obtainStyledAttributes(attrs,R.styleable.ColorPreference,0,0).apply()
        {
            try
            {
                // very important to use the class loader from the passed-in context
                giveMeAClass = context::class.java.classLoader!!
                        .loadClass(getString(R.styleable.MyCustomView_give_me_a_class))
                        .newInstance() // instantiate using 0-args constructor
                        .let {it as SomeCustomInterface}
            }
            finally
            {
                recycle()
            }
        }
    }

3 Comments

In AS 4.0 Canary, I had to declare the attr outside of the styleable as well for it to compile.
@TheWanderer Hey! Can you post an example please? or modify my answer, please? You're right, this solution is not working for me anymore, and my old code is breaking, but I'm not sure how to declare it outside the styleable...i just added format="string" for now.. Thank you!!
Just add an attr tag right under the opening resources tag with the same name and a format specified.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.