The warning/error message (Use '$' instead of '.' for inner classes) was thrown when I tried to create a custom view element inside java sub class.
I tried to make it like so :
<com.example.myapp.CustomClass.Layout
xmlns:android="http://schemas.android.com/apk/res/android"
...>
To solve the error it had to be written the following way:
<view class="com.example.myapp.CustomClass$Layout"
xmlns:android="http://schemas.android.com/apk/res/android"
...>
Related
Trying to dynamically set the layout using databinding but I can't seem to get the ternary operator to work right. Must be missing escape character or something.
<include
android:id="#+id/setting"
bind:settingsViewModel="#{settingsViewModel}"
layout="#{settingsViewModel.configFlag ? #layout/settings_v1 :#layout/settings_v2}" />
Seems simple enough but errors with "****/ data binding error ****msg:included value ... must start with #layout/. "
The answer to this is that you cannot do this. Layout is called before and so this logic cannot be done before hand.
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').
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.
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()
}
}
}
Let's say that I created a custom view called MyView and want to use it in the xml and the view is located in com.example package. I need to do something like this:
<com.example.MyView
......
/>
I need to write the package name every time I use the view. What if I have a long package name?
<what.a.long.long.long.loooooong.packagename.MyView
......
/>
That just looks ugly. Is it possible to shorten the package name? Do I need to do something in the AndroidManifest.xml file?
Define your own namespace:
<Layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:x="what.a.long.long.long.loooooong.packagename."
>
<x:MyView>
</x:MyView>
</Layout>
xmlns:x spefifies that all tags that start with <x: should be looked up in package that is defined in the namespace definition (what.a.long.long.long.loooooong.packagename. in this case).
You can even use the namespace within the tag itself:
<x:MyView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:x="what.a.long.long.long.loooooong.packagename."
/>
You can use my library XmlTag. It lets you use short name of every View that you annotate with #XmlTag.
I love fragments - BUT renaming the classes is a real pain if the fragment class is referenced in an xml like this:
<fragment
android:id="#+id/listFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.pkg1.Screens.MyFragmentClass" >
Now when renaming MyFragmentClass with its java file renames only JAVA files - all the xml referenced stay the same.
Is there a "secret" way to rename so that also the xml references get updated?
Not particularly secret, but you could use Eclipse to do a File Search, use a file name pattern of *.xml, and replace "class="com.pkg1.Screens.MyFragmentClass"" with whatever you're renaming it to...?
I've read the documentation about Fragments in the Android Developer Guide and I've seen that sometimes they specify the class to instantiate with the Fragment tag attribute android:name and sometime they use the class: attribute:
<fragment
android:name="com.example.news.ArticleReaderFragment"
android:id="#+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment
class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="#+id/titles"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
Are android:name and class: interchangeable? If I use the autocompletion function in Eclipse, they both show the same documentation tip (i.e. the attribute provides the class name to be instantiated). Maybe you must use the second one when the class to be instantiated has a name which is different from the java file name, like TitlesFragment which is in the FragmentLayout.java file? Or can I use the syntax package.fileDOTjava$Class also with the android:name attribute?
I'd like to have some documentation for XML tags and attributes as for Android Java Classes (I've asked about it in another question).
As Activity.onCreateView source says:
String fname = attrs.getAttributeValue(null, "class");
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);
if (fname == null) {
fname = a.getString(com.android.internal.R.styleable.Fragment_name);
}
That seemingly means that program looks "class" attribute first. And on fail looks "name" attribute.
So as far as it's true using "class" if more efficient.
Are android:name and class: interchangeable?
Presumably, yes. I have only used class, and that seems to be what most of Google's examples use, but I do see where they use android:name in some samples. Unfortunately, there is no formal and complete documentation for <fragment>.
Sorry all experts are here, I may be wrong but as per my knowledge android:name attribute of fragment is used to find fragment, when we use getFragmentByTag() method of fragmentManager class.
also android:class attribute is used to find fragment class which we generally include for static fragment.
Hope this will help..
thanks